From: moinejf@free.fr (Jean-Francois Moine)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] ARM: dove: add a kms/drm driver
Date: Thu, 16 May 2013 13:28:22 +0200 [thread overview]
Message-ID: <20130516132822.09b883cf@armhf> (raw)
This patch adds a KMS/DRM video driver for the LCD and display
controllers of the Marvell's Dove SoC.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
---
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/dove/Kconfig | 10 +
drivers/gpu/drm/dove/Makefile | 6 +
drivers/gpu/drm/dove/dove_crtc.c | 1378 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/dove/dove_dcon.h | 64 +++
drivers/gpu/drm/dove/dove_drv.c | 380 +++++++++++++
drivers/gpu/drm/dove/dove_drv.h | 93 ++++
drivers/gpu/drm/dove/dove_ec.c | 570 ++++++++++++++++++++
drivers/gpu/drm/dove/dove_lcd.h | 519 ++++++++++++++++++
10 files changed, 3023 insertions(+)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b16c50e..c6e4f4f 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -220,3 +220,5 @@ source "drivers/gpu/drm/omapdrm/Kconfig"
source "drivers/gpu/drm/tilcdc/Kconfig"
source "drivers/gpu/drm/qxl/Kconfig"
+
+source "drivers/gpu/drm/dove/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1c9f243..6428683 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -52,4 +52,5 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
obj-$(CONFIG_DRM_QXL) += qxl/
+obj-$(CONFIG_DRM_DOVE) += dove/
obj-y += i2c/
diff --git a/drivers/gpu/drm/dove/Kconfig b/drivers/gpu/drm/dove/Kconfig
new file mode 100644
index 0000000..465dc4d
--- /dev/null
+++ b/drivers/gpu/drm/dove/Kconfig
@@ -0,0 +1,10 @@
+config DRM_DOVE
+ tristate "DRM Support for Marvell Dove"
+ depends on DRM && ARCH_DOVE
+ depends on OF
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
+ help
+ Choose this option if you have a Marvell Dove chipset.
+ If M is selected the module will be called dove-drm.
diff --git a/drivers/gpu/drm/dove/Makefile b/drivers/gpu/drm/dove/Makefile
new file mode 100644
index 0000000..3758a19
--- /dev/null
+++ b/drivers/gpu/drm/dove/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Marvell Dove's DRM device driver
+#
+
+dove-drm-objs := dove_drv.o dove_crtc.o dove_ec.o
+obj-$(CONFIG_DRM_DOVE) += dove-drm.o
diff --git a/drivers/gpu/drm/dove/dove_crtc.c b/drivers/gpu/drm/dove/dove_crtc.c
new file mode 100644
index 0000000..9e397e7
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_crtc.c
@@ -0,0 +1,1378 @@
+/*
+ * Marvell Dove DRM driver - CRTC
+ *
+ * Copyright (C) 2013
+ * Jean-Francois Moine <moinejf@free.fr>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/of_irq.h>
+
+#include "dove_drv.h"
+#include "dove_lcd.h"
+
+#define DOVE_LCD_REG_BASE_MASK 0xfffff
+#define DOVE_LCD0_REG_BASE 0x20000
+#define DOVE_LCD1_REG_BASE 0x10000
+
+#define to_dove_lcd(x) container_of(x, struct dove_lcd, crtc)
+
+static inline void dove_write(struct dove_lcd *dove_lcd, u32 reg, u32 data)
+{
+ writel(data, dove_lcd->mmio + reg);
+}
+static inline u32 dove_read(struct dove_lcd *dove_lcd, u32 reg)
+{
+ return readl(dove_lcd->mmio + reg);
+}
+static inline void dove_set(struct dove_lcd *dove_lcd, u32 reg, u32 mask)
+{
+ dove_write(dove_lcd, reg, dove_read(dove_lcd, reg) | mask);
+}
+static inline void dove_clear(struct dove_lcd *dove_lcd, u32 reg, u32 mask)
+{
+ dove_write(dove_lcd, reg, dove_read(dove_lcd, reg) & ~mask);
+}
+
+/*
+ * vertical blank functions
+ */
+u32 dove_vblank_count(struct drm_device *dev, int crtc)
+{
+ struct dove_lcd *dove_lcd = dove_drm.lcds[crtc];
+
+ return STA_GRA_FRAME_COUNT(dove_read(dove_lcd, SPU_IRQ_ISR));
+}
+
+int dove_enable_vblank(struct drm_device *dev, int crtc)
+{
+ struct dove_lcd *dove_lcd = dove_drm.lcds[crtc];
+
+#ifdef HANDLE_INTERLACE
+ dove_lcd->vblank_enabled = 1;
+#endif
+ dove_set(dove_lcd, SPU_IRQ_ENA, IRQ_GRA_FRAME_DONE);
+ return 0;
+}
+
+void dove_disable_vblank(struct drm_device *dev, int crtc)
+{
+ struct dove_lcd *dove_lcd = dove_drm.lcds[crtc];
+
+#ifdef HANDLE_INTERLACE
+ dove_lcd->vblank_enabled = 0;
+ if (!dove_lcd->v_sync0)
+#endif
+ dove_clear(dove_lcd, SPU_IRQ_ENA, IRQ_GRA_FRAME_DONE);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int dove_lcd_regs_show(struct seq_file *m,
+ struct dove_lcd *dove_lcd)
+{
+ u32 x, shl, shh, total_v, total_h, active_h, active_v;
+ u32 orig_buff_x, orig_buff_y, zoomed_x, zoomed_y;
+ unsigned i;
+
+ seq_printf(m, "\t\t*** LCD %d ***\n", dove_lcd->num);
+
+ /* Get resolution */
+ x = dove_read(dove_lcd, LCD_SPU_V_H_ACTIVE);
+ active_h = H_LCD(x);
+ active_v = V_LCD(x);
+
+ /* Get total line */
+ x = dove_read(dove_lcd, LCD_SPUT_V_H_TOTAL);
+ total_h = H_LCD(x);
+ total_v = V_LCD(x);
+ seq_printf(m, "----total-------------------------<%4dx%4d>"
+ "-------------------------\n"
+ "----active--------------|", total_h, total_v);
+
+ /* Get H Timings */
+ x = dove_read(dove_lcd, LCD_SPU_H_PORCH);
+ shl = F_LCD(x);
+ shh = B_LCD(x);
+ seq_printf(m, "->front porch(%d)->hsync(%d)->back porch(%d)\n",
+ shl, total_h - shl -shh - active_h, shh);
+
+ seq_printf(m, "|\t\t\t|\n"
+ "|\t\t\t|\n"
+ "|\t<%4dx%4d>\t|\n"
+ "|\t\t\t|\n"
+ "|\t\t\t|\n"
+ "------------------------|\n", active_h, active_v);
+
+ /* Get V Timings */
+ x = dove_read(dove_lcd, LCD_SPU_V_PORCH);
+ shl = F_LCD(x);
+ shh = B_LCD(x);
+ seq_printf(m, "|\n|front porch(%d)\n|vsync(%d)\n|back porch(%d)\n",
+ shl, total_v - shl - shh - active_v, shh);
+ seq_printf(m, "----------------------------------"
+ "-----------------------------------\n");
+
+ /* Get Line Pitch */
+ x = dove_read(dove_lcd, LCD_CFG_GRA_PITCH);
+ shl = x & 0x0000ffff;
+ seq_printf(m, "gfx line pitch in memory is <%d>\n",
+ shl);
+
+ /* Get scaling info */
+ x = dove_read(dove_lcd, LCD_SPU_GRA_HPXL_VLN);
+ orig_buff_x = H_LCD(x);
+ orig_buff_y = V_LCD(x);
+ x = dove_read(dove_lcd, LCD_SPU_GZM_HPXL_VLN);
+ zoomed_x = H_LCD(x);
+ zoomed_y = V_LCD(x);
+ seq_printf(m, "Scaled from <%dx%d> to <%dx%d>\n",
+ orig_buff_x, orig_buff_y, zoomed_x, zoomed_y);
+
+ seq_printf(m, "======================================\n");
+
+ for (i = 0x0080; i <= 0x01c4; i += 4) {
+ x = dove_read(dove_lcd, i);
+ seq_printf(m, "0x%04x 0x%08x\n", i, x);
+ }
+ return 0;
+}
+
+static int dove_regs_show(struct seq_file *m, void *arg)
+{
+ struct dove_lcd *dove_lcd;
+ unsigned i;
+
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd)
+ dove_lcd_regs_show(m, dove_lcd);
+ }
+ return 0;
+}
+
+static struct drm_info_list dove_debugfs_list[] = {
+ { "lcd", dove_regs_show, 0 },
+ { "fb", drm_fb_cma_debugfs_show, 0 },
+};
+
+int dove_debugfs_init(struct drm_minor *minor)
+{
+ struct drm_device *dev = minor->dev;
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ ret = drm_debugfs_create_files(dove_debugfs_list,
+ ARRAY_SIZE(dove_debugfs_list),
+ minor->debugfs_root, minor);
+ if (ret)
+ dev_err(dev->dev, "could not install dove_debugfs_list\n");
+
+ return ret;
+}
+
+void dove_debugfs_cleanup(struct drm_minor *minor)
+{
+ drm_debugfs_remove_files(dove_debugfs_list,
+ ARRAY_SIZE(dove_debugfs_list), minor);
+}
+#endif
+
+static void dove_update_base(struct dove_lcd *dove_lcd)
+{
+ struct drm_crtc *crtc = &dove_lcd->crtc;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct drm_gem_cma_object *gem;
+ unsigned int depth, bpp;
+ dma_addr_t start;
+
+ drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+ start = gem->paddr + fb->offsets[0] +
+ crtc->y * fb->pitches[0] +
+ crtc->x * bpp / 8;
+
+ dove_write(dove_lcd, LCD_CFG_GRA_START_ADDR0, start);
+#ifdef HANDLE_INTERLACE
+ if (dove_lcd->crtc.mode.mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ dove_write(dove_lcd, LCD_CFG_GRA_START_ADDR1,
+ start + fb->pitches[0]);
+ dove_write(dove_lcd, LCD_CFG_GRA_PITCH, fb->pitches[0] * 2);
+ return;
+ }
+#endif
+ dove_write(dove_lcd, LCD_CFG_GRA_START_ADDR1, start);
+ dove_write(dove_lcd, LCD_CFG_GRA_PITCH, fb->pitches[0]);
+}
+
+static void set_frame_timings(struct dove_lcd *dove_lcd)
+{
+ struct drm_crtc *crtc = &dove_lcd->crtc;
+ const struct drm_display_mode *mode = &crtc->mode;
+ u32 h_active, v_active, h_orig, v_orig, h_zoom, v_zoom;
+ u32 hfp, hbp, vfp, vbp, hs, vs, v_total;
+ u32 x;
+
+ /*
+ * Calc active size, zoomed size, porch.
+ */
+ h_active = h_zoom = mode->hdisplay;
+ v_active = v_zoom = mode->vdisplay;
+ hfp = mode->hsync_start - mode->hdisplay;
+ hbp = mode->htotal - mode->hsync_end;
+ vfp = mode->vsync_start - mode->vdisplay;
+ vbp = mode->vtotal - mode->vsync_end;
+ hs = mode->hsync_end - mode->hsync_start;
+ vs = mode->vsync_end - mode->vsync_start;
+
+ /*
+ * Calc original size.
+ */
+ h_orig = h_active;
+ v_orig = v_active;
+
+#ifdef HANDLE_INTERLACE
+ /* interlaced workaround */
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ v_active /= 2;
+ v_zoom /= 2;
+ v_orig /= 2;
+ }
+#endif
+
+ /* calc total width and height */
+ v_total = v_active + vfp + vs + vbp;
+
+ /* apply setting to registers */
+ dove_write(dove_lcd, LCD_SPU_V_H_ACTIVE, LCD_H_V(h_active, v_active));
+ dove_write(dove_lcd, LCD_SPU_GRA_HPXL_VLN, LCD_H_V(h_orig, v_orig));
+ dove_write(dove_lcd, LCD_SPU_GZM_HPXL_VLN, LCD_H_V(h_zoom, v_zoom));
+ dove_write(dove_lcd, LCD_SPU_H_PORCH, LCD_F_B(hfp, hbp));
+ dove_write(dove_lcd, LCD_SPU_V_PORCH, LCD_F_B(vfp, vbp));
+ dove_write(dove_lcd, LCD_SPUT_V_H_TOTAL,
+ LCD_H_V(mode->htotal, v_total));
+
+ /* configure vsync adjust logic */
+ x = dove_read(dove_lcd, LCD_TV_CONTROL1);
+ x &= ~(VSYNC_L_OFFSET_MASK | VSYNC_H_OFFSET_MASK);
+ x |= VSYNC_OFFSET_EN | /* VSYNC adjust enable */
+ VSYNC_L_OFFSET(h_active + hfp) |
+ VSYNC_H_OFFSET(h_active + hfp);
+#ifdef HANDLE_INTERLACE
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ dove_lcd->v_sync0 = VSYNC_L_OFFSET(h_active + hfp) |
+ VSYNC_H_OFFSET(h_active + hfp);
+ dove_lcd->v_sync1 = VSYNC_L_OFFSET(h_active / 2 + hfp) |
+ VSYNC_H_OFFSET(h_active / 2 + hfp);
+ } else {
+ dove_lcd->v_sync0 = 0;
+ }
+#endif
+ dove_write(dove_lcd, LCD_TV_CONTROL1, x);
+}
+
+static int dove_set_clock(struct dove_lcd *dove_lcd)
+{
+ struct drm_crtc *crtc = &dove_lcd->crtc;
+ const struct drm_display_mode *mode = &crtc->mode;
+ struct clk *clk;
+ u32 x, needed_pixclk, ref_clk, div, fract;
+ int clk_src;
+
+ fract = 0;
+ needed_pixclk = mode->clock * 1000;
+#ifdef HANDLE_INTERLACE
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ needed_pixclk /= 2;
+#endif
+
+ /* first check if pixclk is multiple of current clock */
+ clk_src = dove_lcd->clk_src;
+ clk = dove_lcd->clk[clk_src];
+ ref_clk = clk_get_rate(clk);
+
+ DRM_DEBUG_DRIVER("clk src %d rate %u needed %u div %u mod %u\n",
+ clk_src, ref_clk, needed_pixclk,
+ ref_clk / needed_pixclk, ref_clk % needed_pixclk);
+
+ if (ref_clk % needed_pixclk == 0) {
+ div = ref_clk / needed_pixclk;
+ goto set_clock;
+ }
+
+ /* try to set current clock to requested pixclk */
+ clk_set_rate(clk, needed_pixclk);
+ ref_clk = clk_get_rate(clk);
+ if (ref_clk == needed_pixclk) {
+ div = 1;
+ goto set_clock;
+ }
+
+ /* check if any other clock can set pixclk directly */
+ for (clk_src = 0; clk_src < MAX_CLK; clk_src++) {
+ clk = dove_lcd->clk[clk_src];
+ if (!clk)
+ continue;
+
+ /* try to set clock to requested pixclk */
+ clk_set_rate(clk, needed_pixclk);
+ ref_clk = clk_get_rate(clk);
+
+ if (ref_clk % needed_pixclk == 0) {
+ div = ref_clk / needed_pixclk;
+ goto set_clock;
+ }
+ }
+
+ /* fall back to default fix clock source LCD or AXI */
+ if (dove_lcd->clk[SCLK_SRC_PLLDIV])
+ clk_src = SCLK_SRC_PLLDIV;
+ else
+ clk_src = SCLK_SRC_AXI;
+ clk = dove_lcd->clk[clk_src];
+
+ clk_set_rate(clk, needed_pixclk);
+ ref_clk = clk_get_rate(clk);
+
+ /* use internal divider */
+ if (false) {
+/*fixme: does not work*/
+ ref_clk /= 1000;
+ needed_pixclk /= 1000;
+ x = (ref_clk * 0x1000 + needed_pixclk - 1) / needed_pixclk;
+ div = x >> 12;
+ if (div < 1)
+ div = 1;
+ else
+ fract = x & 0xfff;
+ } else {
+ div = (ref_clk + needed_pixclk - 1) / needed_pixclk;
+ if (div < 1)
+ div = 1;
+ }
+
+set_clock:
+ dove_lcd->clk_src = clk_src;
+ DRM_DEBUG_DRIVER("set clk src %d ref %u div %u fract %u needed %u\n",
+ clk_src, ref_clk, div, fract, needed_pixclk);
+ x = SET_SCLK(clk_src, div, fract);
+ dove_write(dove_lcd, LCD_CFG_SCLK_DIV, x);
+ return 0;
+}
+
+static void set_dma_control(struct dove_lcd *dove_lcd)
+{
+ const struct drm_display_mode *mode = &dove_lcd->crtc.mode;
+ u32 x;
+ int fmt, rbswap;
+
+ rbswap = 1; /* default */
+ switch (dove_lcd->crtc.fb->pixel_format) {
+ case DRM_FORMAT_BGR888:
+ rbswap = 0;
+ case DRM_FORMAT_RGB888:
+ fmt = GMODE_RGB888PACKED;
+ break;
+ case DRM_FORMAT_XBGR8888:
+ rbswap = 0;
+ case DRM_FORMAT_XRGB8888: /* depth 24 */
+ fmt = GMODE_RGBA888;
+ break;
+ case DRM_FORMAT_ABGR8888:
+ rbswap = 0;
+ case DRM_FORMAT_ARGB8888: /* depth 32 */
+ fmt = GMODE_RGB888UNPACKED;
+ break;
+ case DRM_FORMAT_YVYU:
+ rbswap = 0;
+ case DRM_FORMAT_YUYV:
+ fmt = GMODE_YUV422PACKED;
+ break;
+ case DRM_FORMAT_YVU422:
+ rbswap = 0;
+ case DRM_FORMAT_YUV422:
+ fmt = GMODE_YUV422PLANAR;
+ break;
+ case DRM_FORMAT_YVU420:
+ rbswap = 0;
+ default:
+/* case DRM_FORMAT_YUV420: */
+ fmt = GMODE_YUV420PLANAR;
+ break;
+ }
+
+ x = dove_read(dove_lcd, LCD_SPU_DMA_CTRL0);
+ x &= ~(CFG_PALETTE_ENA | /* true color */
+ CFG_GRAFORMAT_MASK |
+ CFG_GRA_SWAPRB |
+ CFG_GRA_FTOGGLE);
+ x |= CFG_GRA_ENA | /* graphic enable */
+ CFG_GRA_HSMOOTH; /* horiz. smooth scaling */
+ x |= CFG_GRAFORMAT(fmt);
+
+ if (!rbswap)
+ x |= CFG_GRA_SWAPRB;
+#ifdef HANDLE_INTERLACE
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ x |= CFG_GRA_FTOGGLE;
+#endif
+ dove_write(dove_lcd, LCD_SPU_DMA_CTRL0, x);
+
+ /*
+ * trigger DMA on the falling edge of vsync if vsync is
+ * active low, or on the rising edge if vsync is active high
+ */
+ if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+ dove_set(dove_lcd, LCD_SPU_DMA_CTRL1, CFG_VSYNC_INV);
+}
+
+/* this function is called on mode DRM_MODE_DPMS_ON
+ * and also at loading time with gpio_only set */
+static void set_dumb_panel_control(struct dove_lcd *dove_lcd,
+ int gpio_only)
+{
+ const struct drm_display_mode *mode = &dove_lcd->crtc.mode;
+ u32 x;
+
+ x = 0;
+ if (dove_lcd->dpms == DRM_MODE_DPMS_ON)
+ x = CFG_DUMB_ENA;
+ if (!gpio_only) {
+ if (dove_lcd->dpms == DRM_MODE_DPMS_ON)
+ /*
+ * When dumb interface isn't under 24bit
+ * It might be under SPI or GPIO. If set
+ * to 0x7 will force LCD_D[23:0] output
+ * blank color and damage GPIO and SPI
+ * behavior.
+ */
+ x |= CFG_DUMBMODE(DUMB24_RGB888_0);
+ else
+ x |= CFG_DUMBMODE(7);
+/*fixme
+ if (mode->flags & FB_SYNC_COMP_HIGH_ACT)
+ x |= CFG_INV_COMPSYNC;
+*/
+ if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+ x |= CFG_INV_VSYNC;
+
+ /* Following is a weired workaround. This bit shouldn't be set
+ * For now, if it's 1080p or 720 then don't set HOR_HIGH_ACT */
+ if ((mode->hdisplay == 1920 && mode->vdisplay == 1080) ||
+ (mode->hdisplay == 1280 && mode->vdisplay == 720))
+ /* Do nothing */
+ ;
+ else
+ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+ x |= CFG_INV_HSYNC;
+ }
+
+ dove_write(dove_lcd, LCD_SPU_DUMB_CTRL, x);
+}
+
+void dove_crtc_start(struct dove_lcd *dove_lcd)
+{
+ struct drm_crtc *crtc = &dove_lcd->crtc;
+ struct drm_display_mode *mode = &crtc->mode;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (mode->clock == 0) {
+ dev_err(dove_lcd->dev, "crtc_start: no clock!\n");
+ dove_lcd->dpms = DRM_MODE_DPMS_OFF;
+ return;
+ }
+
+ set_frame_timings(dove_lcd);
+ if (dove_set_clock(dove_lcd) < 0)
+ return;
+ set_dma_control(dove_lcd);
+ dove_update_base(dove_lcd);
+ set_dumb_panel_control(dove_lcd, 0);
+
+#ifdef HANDLE_INTERLACE
+ if (dove_lcd->v_sync0) { /* interlace mode on */
+ dove_set(dove_lcd, SPU_IRQ_ENA, IRQ_GRA_FRAME_DONE);
+ } else { /* interlace mode off */
+ if (!dove_lcd->vblank_enabled)
+ dove_clear(dove_lcd, SPU_IRQ_ENA, IRQ_GRA_FRAME_DONE);
+ }
+#endif
+
+ DRM_DEBUG_DRIVER("start %s@%d\n",
+ crtc->mode.name, crtc->mode.vrefresh);
+}
+
+void dove_crtc_stop(struct dove_lcd *dove_lcd)
+{
+ DRM_DEBUG_DRIVER("\n");
+
+ dove_clear(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_GRA_ENA);
+ dove_clear(dove_lcd, LCD_SPU_DUMB_CTRL, CFG_DUMB_ENA);
+#ifdef HANDLE_INTERLACE
+ if (dove_lcd->v_sync0
+ && !dove_lcd->vblank_enabled)
+ dove_clear(dove_lcd, SPU_IRQ_ENA, IRQ_GRA_FRAME_DONE);
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+ * cursor
+ */
+
+/* load the hardware cursor */
+static int load_cursor(struct dove_lcd *dove_lcd,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ int data_len)
+{
+ struct drm_gem_object *obj;
+ struct drm_gem_cma_object *cma_obj;
+ u8 *p_pixel;
+ u32 u, val;
+ u32 ram, color;
+ int i, j, ret;
+
+ obj = drm_gem_object_lookup(dove_drm.drm, file_priv, handle);
+ if (!obj)
+ return -ENOENT;
+
+ if (!obj->map_list.map) {
+ dev_warn(dove_lcd->dev, "cursor not mapped\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (data_len != obj->size) {
+ dev_warn(dove_lcd->dev, "bad cursor size\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cma_obj = to_drm_gem_cma_obj(obj);
+ p_pixel = cma_obj->vaddr;
+
+ u = CFG_SRAM_INIT_WR_RD(SRAMID_INIT_WRITE) |
+ CFG_SRAM_ADDR_LCDID(SRAMID_HWC);
+ ram = CFG_SRAM_INIT_WR_RD(SRAMID_INIT_WRITE);
+
+ /* load the RGBA cursor to SRAM */
+ for (i = 0; i < data_len / 4 / 4; i++) {
+ color = (p_pixel[3 * 4 + 0] << 24) | /* red */
+ (p_pixel[2 * 4 + 0] << 16) |
+ (p_pixel[1 * 4 + 0] << 8) |
+ p_pixel[0];
+ dove_write(dove_lcd, LCD_SPU_SRAM_WRDAT, color);
+ dove_write(dove_lcd, LCD_SPU_SRAM_CTRL,
+ ram | CFG_SRAM_ADDR_LCDID(SRAMID_HWC32_RAM1));
+ color = (p_pixel[3 * 4 + 1] << 24) | /* green */
+ (p_pixel[2 * 4 + 1] << 16) |
+ (p_pixel[1 * 4 + 1] << 8) |
+ p_pixel[1];
+ dove_write(dove_lcd, LCD_SPU_SRAM_WRDAT, color);
+ dove_write(dove_lcd, LCD_SPU_SRAM_CTRL,
+ ram | CFG_SRAM_ADDR_LCDID(SRAMID_HWC32_RAM2));
+ color = (p_pixel[3 * 4 + 2] << 24) | /* blue */
+ (p_pixel[2 * 4 + 2] << 16) |
+ (p_pixel[1 * 4 + 2] << 8) |
+ p_pixel[2];
+ dove_write(dove_lcd, LCD_SPU_SRAM_WRDAT, color);
+ dove_write(dove_lcd, LCD_SPU_SRAM_CTRL,
+ ram | CFG_SRAM_ADDR_LCDID(SRAMID_HWC32_RAM3));
+ p_pixel += 4 * 4;
+ if ((++ram & 0xff) == 0) {
+ ram -= 0x100; /* I[7:0] */
+ ram += 1 << 12; /* J[1:0] */
+ }
+ }
+
+ /* set the transparency */
+ p_pixel = cma_obj->vaddr;
+ for (i = 0; i < data_len / 16 / 4; i++) {
+ val = 0;
+ for (j = 16 * 4 - 4; j >= 0 ; j -= 4) {
+ val <<= 2;
+ if (p_pixel[j + 3]) /* alpha */
+ val |= 1; /* not transparent */
+ }
+ dove_write(dove_lcd, LCD_SPU_SRAM_WRDAT, val);
+ dove_write(dove_lcd, LCD_SPU_SRAM_CTRL, u++);
+ p_pixel += 16 * 4;
+ }
+ ret = 0;
+out:
+ drm_gem_object_unreference_unlocked(obj);
+ return ret;
+}
+
+static int dove_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+ int ret;
+
+ DRM_DEBUG_DRIVER("%dx%d handle %d\n", width, height, handle);
+
+ /* disable cursor */
+ dove_clear(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_HWC_ENA);
+
+ if (!handle)
+ return 0; /* cursor off */
+
+ if (width != 64 || height != 64) {
+ dev_err(dove_lcd->dev, "bad cursor size\n");
+ return -EINVAL;
+ }
+
+ /* load the cursor */
+ ret = load_cursor(dove_lcd, file_priv, handle, width * height * 4);
+ if (ret < 0)
+ return ret;
+
+ /* set cursor size */
+ dove_write(dove_lcd, LCD_SPU_HWC_HPXL_VLN, LCD_H_V(width, height));
+
+ /* enable cursor */
+ dove_set(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_HWC_ENA);
+
+ return 0;
+}
+
+static int dove_cursor_move(struct drm_crtc *crtc,
+ int x, int y)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ dove_clear(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_HWC_ENA);
+ dove_write(dove_lcd, LCD_SPU_HWC_OVSA_HPXL_VLN, LCD_H_V(x, y));
+ dove_set(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_HWC_ENA);
+ return 0;
+}
+
+static void dove_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+
+ DRM_DEBUG_DRIVER("\n");
+
+ WARN_ON(dove_lcd->dpms == DRM_MODE_DPMS_ON);
+
+ drm_crtc_cleanup(crtc);
+}
+
+static int dove_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+ struct drm_device *drm = dove_drm.drm;
+ unsigned long flags;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ spin_lock_irqsave(&drm->event_lock, flags);
+ if (dove_lcd->event) {
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+ dev_err(drm->dev, "already pending page flip!\n");
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+
+ crtc->fb = fb;
+ dove_update_base(dove_lcd);
+
+ if (event) {
+ event->pipe = 0;
+ spin_lock_irqsave(&drm->event_lock, flags);
+ dove_lcd->event = event;
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+ drm_vblank_get(drm, dove_lcd->num);
+ }
+
+ return 0;
+}
+
+static void dove_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+
+ /* we really only care about on or off */
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
+ DRM_DEBUG_DRIVER("dpms %s\n", mode == DRM_MODE_DPMS_ON ? "on" : "off");
+
+ if (dove_lcd->dpms == mode)
+ return;
+
+ dove_lcd->dpms = mode;
+
+ if (mode == DRM_MODE_DPMS_ON)
+ dove_crtc_start(dove_lcd);
+ else
+ dove_crtc_stop(dove_lcd);
+}
+
+static bool dove_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ DRM_DEBUG_DRIVER("\n");
+ if (adjusted_mode->vrefresh == 0) {
+/* drm_mode_set_name(adjusted_mode); */
+ adjusted_mode->vrefresh = drm_mode_vrefresh(adjusted_mode);
+ DRM_DEBUG_DRIVER("%s@%d\n",
+ adjusted_mode->name, adjusted_mode->vrefresh);
+ }
+ return true;
+}
+
+static void dove_crtc_prepare(struct drm_crtc *crtc)
+{
+ DRM_DEBUG_DRIVER("\n");
+ dove_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void dove_crtc_commit(struct drm_crtc *crtc)
+{
+ DRM_DEBUG_DRIVER("\n");
+/* dove_crtc_dpms(crtc, DRM_MODE_DPMS_ON); */
+}
+
+static int dove_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ unsigned int bandwidth;
+ DRM_DEBUG_DRIVER("\n");
+
+ if (mode->hdisplay > 2048)
+ return MODE_VIRTUAL_X;
+
+ /* width must be multiple of 16 */
+ if (mode->hdisplay & 0xf)
+ return MODE_VIRTUAL_X;
+
+ if (mode->vdisplay > 2048)
+ return MODE_VIRTUAL_Y;
+
+ /* filter out modes that would require too much memory bandwidth: */
+ bandwidth = mode->hdisplay * mode->vdisplay * drm_mode_vrefresh(mode);
+ if (bandwidth > 1920 * 1080 * 60)
+ return MODE_BAD;
+
+/*fixme: is this useful? */
+ mode = &crtc->mode;
+ if (mode->vrefresh == 0) {
+ drm_mode_set_name(mode);
+ mode->vrefresh = drm_mode_vrefresh(mode);
+ DRM_DEBUG_DRIVER("%s@%d\n", mode->name, mode->vrefresh);
+ }
+ return MODE_OK;
+}
+
+static int dove_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+
+ DRM_DEBUG_DRIVER("\n");
+ dove_update_base(dove_lcd);
+ return 0;
+}
+
+/* mandatory drm function */
+static void dove_crtc_load_lut(struct drm_crtc *crtc)
+{
+ DRM_DEBUG_DRIVER("\n");
+}
+
+static const struct drm_crtc_funcs dove_crtc_funcs = {
+ .cursor_set = dove_cursor_set,
+ .cursor_move = dove_cursor_move,
+ .destroy = dove_crtc_destroy,
+ .set_config = drm_crtc_helper_set_config,
+ .page_flip = dove_crtc_page_flip,
+};
+
+static const struct drm_crtc_helper_funcs dove_crtc_helper_funcs = {
+ .dpms = dove_crtc_dpms,
+ .mode_fixup = dove_crtc_mode_fixup,
+ .prepare = dove_crtc_prepare,
+ .commit = dove_crtc_commit,
+ .mode_set = dove_crtc_mode_set,
+ .mode_set_base = dove_crtc_mode_set_base,
+ .load_lut = dove_crtc_load_lut,
+};
+
+void dove_crtc_cancel_page_flip(struct dove_lcd *dove_lcd,
+ struct drm_file *file)
+{
+ struct drm_pending_vblank_event *event;
+ struct drm_device *drm = dove_drm.drm;
+ unsigned long flags;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /*
+ * Destroy the pending vertical blanking event associated with the
+ * pending page flip, if any, and disable vertical blanking interrupts.
+ */
+ spin_lock_irqsave(&drm->event_lock, flags);
+ event = dove_lcd->event;
+ if (event && event->base.file_priv == file) {
+ dove_lcd->event = NULL;
+ event->base.destroy(&event->base);
+ drm_vblank_put(drm, dove_lcd->num);
+ }
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+/* configure default register values */
+static void dove_set_defaults(struct dove_lcd *dove_lcd)
+{
+ u32 x;
+
+ /* set the default clock */
+ if (dove_lcd->clk[SCLK_SRC_PLLDIV])
+ dove_lcd->clk_src = SCLK_SRC_PLLDIV;
+ else
+ dove_lcd->clk_src = SCLK_SRC_AXI;
+ DRM_DEBUG_DRIVER("default clock %d\n", dove_lcd->clk_src);
+
+ x = SET_SCLK(dove_lcd->clk_src, 1, 0);
+ dove_write(dove_lcd, LCD_CFG_SCLK_DIV, x);
+ dove_write(dove_lcd, LCD_SPU_BLANKCOLOR, 0);
+
+ dove_write(dove_lcd, SPU_IOPAD_CONTROL, IOPAD_DUMB24);
+ dove_write(dove_lcd, LCD_CFG_GRA_START_ADDR1, 0);
+ dove_write(dove_lcd, LCD_SPU_GRA_OVSA_HPXL_VLN, 0);
+ dove_write(dove_lcd, LCD_SPU_SRAM_PARA0, 0);
+ dove_write(dove_lcd, LCD_SPU_SRAM_PARA1, CFG_CSB_256x32 |
+ CFG_CSB_256x24 |
+ CFG_CSB_256x8);
+ dove_write(dove_lcd, LCD_SPU_DMA_CTRL1, CFG_VSYNC_TRIG(2) |
+ CFG_GATED_ENA |
+ CFG_PWRDN_ENA |
+ CFG_ALPHA_MODE(2) |
+ CFG_ALPHA(0xff) |
+ CFG_PXLCMD(0x81));
+
+ /*
+ * Fix me: to avoid jiggling issue for high resolution in
+ * dual display, we set watermark to affect LCD AXI read
+ * from MC (default 0x80). Lower watermark means LCD will
+ * do DMA read more often.
+ */
+ x = dove_read(dove_lcd, LCD_CFG_RDREG4F);
+ x &= ~DMA_WATERMARK_MASK;
+ x |= DMA_WATERMARK(0x20);
+
+ /*
+ * Disable LCD SRAM Read Wait State to resolve HWC32 make
+ * system hang while use external clock.
+ */
+ x &= ~LCD_SRAM_WAIT;
+ dove_write(dove_lcd, LCD_CFG_RDREG4F, x);
+
+ /* prepare the hwc32 */
+ dove_set(dove_lcd, LCD_TV_CONTROL1, HWC32_ENABLE);
+
+ /* set hwc32 with 100% static alpha blending factor */
+ dove_write(dove_lcd, LCD_SPU_ALPHA_COLOR1,
+ HWC32_CFG_ALPHA(0xff));
+}
+
+static irqreturn_t dove_lcd_irq(int irq, void *dev_id)
+{
+ struct dove_lcd *dove_lcd = (struct dove_lcd *) dev_id;
+ struct drm_pending_vblank_event *event;
+ struct drm_device *drm = dove_drm.drm;
+ u32 isr;
+ unsigned long flags;
+
+ isr = dove_read(dove_lcd, SPU_IRQ_ISR);
+ dove_write(dove_lcd, SPU_IRQ_ISR, 0);
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (isr & IRQ_GRA_FRAME_DONE) {
+#ifdef HANDLE_INTERLACE
+ if (dove_lcd->v_sync0) {
+ u32 x;
+
+ x = dove_read(dove_lcd, LCD_TV_CONTROL1);
+ x &= ~(VSYNC_L_OFFSET_MASK | VSYNC_H_OFFSET_MASK);
+ if (isr & IRQ_GRA_FRAME0)
+ x |= dove_lcd->v_sync0;
+ else
+ x |= dove_lcd->v_sync1;
+ dove_write(dove_lcd, LCD_TV_CONTROL1, x);
+ }
+ if (dove_lcd->vblank_enabled)
+#endif
+ drm_handle_vblank(drm, dove_lcd->num);
+ spin_lock_irqsave(&drm->event_lock, flags);
+ event = dove_lcd->event;
+ dove_lcd->event = NULL;
+ if (event)
+ drm_send_vblank_event(drm, dove_lcd->num, event);
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+ if (event)
+ drm_vblank_put(drm, dove_lcd->num);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* initialize a lcd */
+static int dove_crtc_init(struct dove_lcd *dove_lcd)
+{
+ struct drm_crtc *crtc = &dove_lcd->crtc;
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ dove_lcd->dpms = DRM_MODE_DPMS_OFF;
+
+ ret = drm_crtc_init(dove_drm.drm, crtc, &dove_crtc_funcs);
+ if (ret < 0)
+ goto fail;
+
+ dove_write(dove_lcd, SPU_IRQ_ENA, 0); /* disable interrupts */
+ ret = devm_request_irq(dove_lcd->dev, dove_lcd->irq, dove_lcd_irq, 0,
+ dove_lcd->name, dove_lcd);
+ if (ret < 0) {
+ dev_err(dove_lcd->dev, "unable to request irq %d\n",
+ dove_lcd->irq);
+ goto fail;
+ }
+
+ if (ret < 0) {
+ dev_err(dove_lcd->dev, "failed to install IRQ handler\n");
+ goto fail;
+ }
+
+ dove_set_defaults(dove_lcd);
+ set_dumb_panel_control(dove_lcd, 1);
+
+ drm_crtc_helper_add(crtc, &dove_crtc_helper_funcs);
+
+ return 0;
+
+fail:
+ dove_crtc_destroy(crtc);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Overlay plane
+ */
+
+static void plane_update_base(struct dove_lcd *dove_lcd,
+ int plane_num,
+ struct drm_framebuffer *fb,
+ int fmt,
+ int x, int y,
+ int w, int h)
+{
+ struct drm_gem_cma_object *gem;
+ unsigned int addr;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ gem = drm_fb_cma_get_gem_obj(fb, plane_num);
+
+ addr = gem->paddr + fb->offsets[0] + y * fb->pitches[0] + x;
+ dove_write(dove_lcd, LCD_SPU_DMA_START_ADDR_Y0, addr);
+
+ switch (fmt) {
+ case VMODE_YUV422PLANAR:
+ case VMODE_YUV420PLANAR:
+ addr += w * h / 2; /* planar */
+ break;
+ }
+ dove_write(dove_lcd, LCD_SPU_DMA_START_ADDR_U0, addr);
+
+ switch (fmt) {
+ case VMODE_YUV422PLANAR:
+ addr += w * h / 2;
+ break;
+ case VMODE_YUV420PLANAR:
+ addr += w * h / 4;
+ break;
+ }
+ dove_write(dove_lcd, LCD_SPU_DMA_START_ADDR_V0, addr);
+
+ switch (fb->pixel_format) {
+ case VMODE_YUV422PACKED:
+ dove_write(dove_lcd, LCD_SPU_DMA_PITCH_YC,
+ LCD_Y_C(w * 2, 0));
+ dove_write(dove_lcd, LCD_SPU_DMA_PITCH_UV, LCD_U_V(w, w));
+ break;
+ default:
+/* case VMODE_YUV422PLANAR: */
+/* case VMODE_YUV420PLANAR: */
+ dove_write(dove_lcd, LCD_SPU_DMA_PITCH_YC, LCD_Y_C(w, 0));
+ dove_write(dove_lcd, LCD_SPU_DMA_PITCH_UV,
+ LCD_U_V(w / 2, w / 2));
+ break;
+ }
+}
+
+static int dove_plane_update(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(crtc);
+ u32 x, x_bk;
+ int fmt, rbswap;
+
+ DRM_DEBUG_DRIVER("%d\n", plane == &dove_lcd->planes[PLANE_VID]);
+
+ if (plane != &dove_lcd->planes[PLANE_VID])
+ return 0;
+ rbswap = 1; /* default */
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_YVYU:
+ rbswap = 0;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ fmt = VMODE_YUV422PACKED;
+ break;
+ case DRM_FORMAT_YVU422:
+ rbswap = 0;
+ case DRM_FORMAT_YUV422:
+ fmt = VMODE_YUV422PLANAR;
+ break;
+ case DRM_FORMAT_YVU420:
+ rbswap = 0;
+ default:
+/* case DRM_FORMAT_YUV420: */
+ fmt = VMODE_YUV420PLANAR;
+ break;
+ }
+
+ x_bk = x = dove_read(dove_lcd, LCD_SPU_DMA_CTRL0);
+ /* clear video layer's field */
+ x &= ~(CFG_YUV2RGB_DMA | CFG_DMA_SWAP_MASK |
+ CFG_DMA_TSTMODE | CFG_DMA_HSMOOTH | CFG_DMA_FTOGGLE |
+ CFG_DMAFORMAT_MASK | CFG_PALETTE_ENA);
+ x |= CFG_DMA_HSMOOTH; /* enable horizontal smooth scaling */
+ x |= CFG_DMAFORMAT(fmt); /* configure hardware pixel format */
+/*fixme: no RGB */
+ if (fb->pixel_format == DRM_FORMAT_UYVY) {
+ x |= CFG_YUV2RGB_DMA;
+ } else if (fmt == VMODE_YUV422PACKED) {
+ x |= CFG_YUV2RGB_DMA |
+ CFG_DMA_SWAPYU |
+ CFG_DMA_SWAPRB;
+ if (rbswap)
+ x |= CFG_DMA_SWAPUV;
+ } else { /* planar */
+ x |= CFG_YUV2RGB_DMA |
+ CFG_DMA_SWAPRB;
+ if (!rbswap)
+ x |= CFG_DMA_SWAPUV;
+ }
+ if (x != x_bk)
+ dove_write(dove_lcd, LCD_SPU_DMA_CTRL0, x);
+
+ /* set the dma addresses */
+ plane_update_base(dove_lcd, PLANE_VID,
+ fb, fmt, src_x, src_y, src_w, src_h);
+
+ /* original size */
+ dove_write(dove_lcd, LCD_SPU_DMA_HPXL_VLN,
+ LCD_H_V(src_w, src_h));
+
+ /* scaled size */
+ dove_write(dove_lcd, LCD_SPU_DZM_HPXL_VLN,
+ LCD_H_V(crtc_w, crtc_h));
+
+ /* update video position offset */
+ dove_write(dove_lcd, LCD_SPUT_DMA_OVSA_HPXL_VLN,
+ LCD_H_V(crtc_x, crtc_y));
+ return 0;
+}
+
+static int dove_plane_disable(struct drm_plane *plane)
+{
+ struct dove_lcd *dove_lcd = to_dove_lcd(plane->crtc);
+
+ DRM_DEBUG_DRIVER("%d\n",
+ plane == &dove_lcd->planes[PLANE_VID]);
+
+ if (plane != &dove_lcd->planes[PLANE_VID])
+ return 0;
+
+ dove_clear(dove_lcd, LCD_SPU_DMA_CTRL0, CFG_DMA_ENA);
+ return 0;
+}
+
+static void dove_plane_destroy(struct drm_plane *plane)
+{
+ dove_plane_disable(plane);
+ drm_plane_cleanup(plane);
+}
+
+static const struct drm_plane_funcs plane_funcs = {
+ .update_plane = dove_plane_update,
+ .disable_plane = dove_plane_disable,
+ .destroy = dove_plane_destroy,
+};
+static const uint32_t gfx_formats[] = {
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVU422,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YUV420,
+};
+static const uint32_t vid_formats[] = {
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVU422,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_UYVY,
+};
+
+static int dove_planes_init(struct dove_lcd *dove_lcd)
+{
+ struct drm_device *drm = dove_drm.drm;
+ struct drm_plane *plane;
+ int ret;
+
+ if (false) {
+ plane = &dove_lcd->planes[PLANE_VID];
+ ret = drm_plane_init(drm, plane, 1 << dove_lcd->num,
+ &plane_funcs,
+ gfx_formats, ARRAY_SIZE(gfx_formats), true);
+ if (ret < 0)
+ return ret;
+ plane->crtc = &dove_lcd->crtc;
+ }
+ plane = &dove_lcd->planes[PLANE_VID];
+ ret = drm_plane_init(drm, plane, 1 << dove_lcd->num,
+ &plane_funcs,
+ vid_formats, ARRAY_SIZE(vid_formats), false);
+ if (ret < 0)
+ return ret;
+ plane->crtc = &dove_lcd->crtc;
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+int dove_lcd_init(struct dove_lcd *dove_lcd)
+{
+ int ret;
+
+ ret = dove_crtc_init(dove_lcd);
+ if (ret < 0)
+ return ret;
+ ret = dove_planes_init(dove_lcd);
+ if (ret < 0)
+ dev_err(dove_lcd->dev, "failed to create the planes\n");
+
+ return ret;
+}
+
+/* at probe time, get the possible LCD clocks */
+static int get_lcd_clocks(struct dove_lcd *dove_lcd)
+{
+ struct device *dev = dove_lcd->dev;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ struct clk *clk;
+ int i, no_clock, ret;
+
+ no_clock = 1;
+ for (i = 0; i < MAX_CLK; i++) {
+
+ /* check first if there is a phandle to the clock */
+ ret = of_parse_phandle_with_args(np,
+ "clocks", "#clock-cells", i,
+ &clkspec);
+ if (ret)
+ continue; /* no defined clock here */
+ of_node_put(clkspec.np);
+
+ /* if no clock driver, ignore this clock */
+ clk = of_clk_get(np, i);
+ if (IS_ERR(clk)) {
+ if (!dove_drm.probe_defer) {
+ dove_drm.probe_defer = 1;
+ return -EPROBE_DEFER;
+ }
+ dev_err(dev, "no driver for clock %i\n", i);
+ continue;
+ }
+ DRM_DEBUG_DRIVER("clock %d ok\n", i);
+ clk_prepare_enable(clk);
+ dove_lcd->clk[i] = clk;
+ no_clock = 0;
+ }
+ if (no_clock) {
+ dev_err(dev, "no available clock\n");
+ return -EINVAL;
+ }
+ if (!dove_lcd->clk[SCLK_SRC_PLLDIV] && !dove_lcd->clk[SCLK_SRC_AXI]) {
+ dev_err(dev, "no fixed clock\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dove_lcd_remove(struct platform_device *pdev)
+{
+ struct dove_lcd *dove_lcd = platform_get_drvdata(pdev);
+ struct clk *clk;
+ int i;
+
+ dove_write(dove_lcd, SPU_IRQ_ENA, 0); /* disable interrupts */
+
+ if (dove_drm.lcds[dove_lcd->num] == dove_lcd)
+ dove_drm.lcds[dove_lcd->num] = NULL;
+
+ for (i = 0; i < MAX_CLK; i++) {
+ clk = dove_lcd->clk[i];
+ if (clk) {
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+ }
+ }
+
+ kfree(dove_lcd);
+ return 0;
+}
+
+static int dove_lcd_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct dove_lcd *dove_lcd;
+ struct resource *res;
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /* bail out early if no DT data */
+ if (!np) {
+ dev_err(dev, "no device-tree\n");
+ return -ENXIO;
+ }
+
+ dove_lcd = kzalloc(sizeof *dove_lcd, GFP_KERNEL);
+ if (!dove_lcd) {
+ dev_err(dev, "failed to allocate private data\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, dove_lcd);
+ dove_lcd->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "failed to get memory resource\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ dove_lcd->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dove_lcd->mmio)) {
+ dev_err(dev, "failed map registers\n");
+ ret = PTR_ERR(dove_lcd->mmio);
+ dove_lcd->mmio = NULL;
+ goto fail;
+ }
+
+ switch (((u32) dove_lcd->mmio) & DOVE_LCD_REG_BASE_MASK) {
+ case DOVE_LCD0_REG_BASE:
+/* dove_lcd->num = 0; */
+ break;
+ case DOVE_LCD1_REG_BASE:
+ dove_lcd->num = 1;
+ break;
+ default:
+ dev_err(dev, "unknown lcd reg base %08x\n",
+ (u32) dove_lcd->mmio);
+ ret = -EINVAL;
+ goto fail;
+ }
+ snprintf(dove_lcd->name, sizeof dove_lcd->name, "dove-lcd%d",
+ dove_lcd->num);
+ dove_drm.lcds[dove_lcd->num] = dove_lcd;
+
+ dove_lcd->irq = irq_of_parse_and_map(np, 0);
+ if (dove_lcd->irq < 0 || dove_lcd->irq == NO_IRQ) {
+ dev_err(dev, "unable to get irq lcd %d\n", dove_lcd->num);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = get_lcd_clocks(dove_lcd);
+ if (ret < 0)
+ goto fail;
+
+ /* check the presence of a possible external slave encoder */
+ ret = dove_ec_probe(dove_lcd);
+ if (ret < 0)
+ goto fail;
+
+ /* init done, try to initialize the drm driver */
+ return dove_probed();
+
+fail:
+ dove_lcd_remove(pdev);
+ return ret;
+}
+
+static struct of_device_id dove_lcd_of_match[] = {
+ { .compatible = "marvell,dove-lcd" },
+ { },
+};
+struct platform_driver dove_lcd_platform_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "dove-lcd",
+ .of_match_table = dove_lcd_of_match,
+ },
+ .probe = dove_lcd_probe,
+ .remove = dove_lcd_remove,
+};
diff --git a/drivers/gpu/drm/dove/dove_dcon.h b/drivers/gpu/drm/dove/dove_dcon.h
new file mode 100644
index 0000000..da2b99c
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_dcon.h
@@ -0,0 +1,64 @@
+/*
+ * Display controller registers of Marvell DOVE
+ *
+ * Copyright (C) 2013
+ * Jean-Francois Moine <moinejf@free.fr>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DOVE_DCON_H_
+#define _DOVE_DCON_H_
+
+/* ------------< DCON register >------------ */
+
+#define DCON_CTL0 0x0000
+#define VGA_CLK_DISABLE BIT(25)
+#define DCON_CLK_DISABLE BIT(24)
+#define DCON_RST BIT(23)
+#define LCD_Disable BIT(17)
+#define Reverse_Scan BIT(10)
+#define LCD_Port_B_Select_MASK 0x00000300
+#define Port_B_Select_LCD1 0x00000000
+#define Port_B_Select_LCD0 0x00000100
+#define Port_B_Select_A_copy 0x00000300
+#define LCD_Port_A_Select_MASK 0x000000c0
+#define Port_A_Select_LCD 0x00000000
+#define Port_A_Select_OLPC 0x00000040
+#define Port_A_Select_Dual 0x00000080
+#define Port_A_Select_ext 0x000000c0
+#define LBUF_EN BIT(5)
+#define DCON_IRQ_CTL 0x0008
+#define IRQ_Control_MASK 0x00ff0000
+#define DITHER_REG_R 0x0050
+#define DITHER_REG_G 0x0054
+#define DITHER_REG_B 0x0058
+#define DCON_DITHER_PAT_RL 0x0060
+#define DCON_DITHER_PAT_RH 0x0064
+#define DCON_DITHER_PAT_GL 0x0068
+#define DCON_DITHER_PAT_GH 0x006c
+#define DCON_DITHER_PAT_BL 0x0070
+#define DCON_DITHER_PAT_BH 0x0074
+#define VGA_Global 0x0080
+#define VGA_CHA 0x0084
+#define VGA_CHB 0x0088
+#define VGA_CHC 0x008c
+#define VGA_CHA_STA 0x0090
+#define VGA_CHB_STA 0x0094
+#define VGA_CHC_STA 0x0098
+#define CT_LUT_INDEX 0x00a4
+#define CT_LUT_DATA 0x00a8
+#define FTDLL_CTL 0x00c0
+
+#endif /* _DOVE_DCON_H_ */
diff --git a/drivers/gpu/drm/dove/dove_drv.c b/drivers/gpu/drm/dove/dove_drv.c
new file mode 100644
index 0000000..e9e77ad
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_drv.c
@@ -0,0 +1,380 @@
+/*
+ * Marvell Dove DRM driver - main
+ *
+ * Copyright (C) 2013
+ * Jean-Francois Moine <moinejf@free.fr>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+
+#include "dove_drv.h"
+
+#define DRIVER_NAME "dove-drm"
+#define DRIVER_DESC "Marvell Dove DRM"
+#define DRIVER_DATE "20130516"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+struct dove_drm dove_drm;
+static struct platform_device *g_pdev;
+static atomic_t probed;
+
+static struct drm_framebuffer *dove_fb_create(struct drm_device *drm,
+ struct drm_file *file_priv,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ DRM_DEBUG_DRIVER("fmt %.4s\n", (char *) &mode_cmd->pixel_format);
+
+ switch (mode_cmd->pixel_format) {
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YUV420:
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ return drm_fb_cma_create(drm, file_priv, mode_cmd);
+}
+
+static void dove_fb_output_poll_changed(struct drm_device *drm)
+{
+ DRM_DEBUG_DRIVER("fb:%d\n", dove_drm.fbdev != NULL);
+ if (dove_drm.fbdev)
+ drm_fbdev_cma_hotplug_event(dove_drm.fbdev);
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+ .fb_create = dove_fb_create,
+ .output_poll_changed = dove_fb_output_poll_changed,
+};
+
+/*
+ * DRM operations:
+ */
+static int dove_unload(struct drm_device *drm)
+{
+ struct dove_lcd *dove_lcd;
+ int i;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd) {
+ if (dove_lcd->planes[PLANE_VID].dev)
+ drm_plane_cleanup(&dove_lcd->planes[PLANE_VID]);
+ if (dove_lcd->planes[PLANE_GFX].dev)
+ drm_plane_cleanup(&dove_lcd->planes[PLANE_GFX]);
+ }
+ }
+ drm_kms_helper_poll_fini(drm);
+ drm_mode_config_cleanup(drm);
+ drm_vblank_cleanup(drm);
+
+ return 0;
+}
+
+/* this function is called when all LCDs and dcon have been probed */
+static int dove_load(struct drm_device *drm, unsigned long flags)
+{
+ struct platform_device *pdev = drm->platformdev;
+ struct dove_lcd *dove_lcd;
+ int i, ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ dove_drm.drm = drm;
+ platform_set_drvdata(pdev, &dove_drm);
+ drm->dev_private = &dove_drm;
+
+ drm_mode_config_init(drm);
+
+/* pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); */
+
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd) {
+ ret = dove_lcd_init(dove_lcd);
+ if (ret < 0)
+ goto fail;
+ ret = dove_ec_init(dove_lcd);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ drm->mode_config.min_width = 0;
+ drm->mode_config.min_height = 0;
+ drm->mode_config.max_width = 2048;
+ drm->mode_config.max_height = 2048;
+ drm->mode_config.funcs = &mode_config_funcs;
+
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (ret < 0) {
+ dev_err(drm->dev, "failed to initialize vblank\n");
+ goto fail;
+ }
+
+ dove_drm.fbdev = drm_fbdev_cma_init(drm,
+ 32, /* bpp */
+ drm->mode_config.num_crtc,
+ drm->mode_config.num_connector);
+
+ drm_kms_helper_poll_init(drm);
+ return 0;
+fail:
+ dove_unload(drm);
+ return ret;
+}
+
+static void dove_preclose(struct drm_device *drm, struct drm_file *file)
+{
+ struct dove_lcd *dove_lcd;
+ int i;
+
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd)
+ dove_crtc_cancel_page_flip(dove_lcd, file);
+ }
+}
+
+static void dove_lastclose(struct drm_device *drm)
+{
+ drm_fbdev_cma_restore_mode(dove_drm.fbdev);
+}
+
+static int dove_gem_cma_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ if (args->height * args->width * args->bpp == 0) {
+ dev_err(dev->dev, "dumb_create %dx%d bpp %d!\n",
+ args->height, args->width, args->bpp);
+ return -ENOMEM;
+ }
+ return drm_gem_cma_dumb_create(file_priv, dev, args);
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .poll = drm_poll,
+ .read = drm_read,
+ .fasync = drm_fasync,
+ .llseek = no_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver dove_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET,
+ .load = dove_load,
+ .unload = dove_unload,
+ .preclose = dove_preclose,
+ .lastclose = dove_lastclose,
+ .get_vblank_counter = dove_vblank_count,
+ .enable_vblank = dove_enable_vblank,
+ .disable_vblank = dove_disable_vblank,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = dove_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_cma_dumb_destroy,
+#ifdef CONFIG_DEBUG_FS
+ .debugfs_init = dove_debugfs_init,
+ .debugfs_cleanup = dove_debugfs_cleanup,
+#endif
+ .fops = &fops,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+};
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * Power management
+ */
+static int dove_pm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct dove_lcd *dove_lcd;
+ int i;
+
+ drm_kms_helper_poll_disable(drm);
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd)
+ dove_crtc_stop(dove_lcd);
+ }
+ return 0;
+}
+
+static int dove_pm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct dove_lcd *dove_lcd;
+ int i;
+
+ for (i = 0; i < MAX_DOVE_LCD; i++) {
+ dove_lcd = dove_drm.lcds[i];
+ if (dove_lcd
+ && dove_lcd->dpms == DRM_MODE_DPMS_ON)
+ dove_crtc_start(dove_lcd);
+ }
+ drm_kms_helper_poll_enable(drm);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops dove_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dove_pm_suspend, dove_pm_resume)
+};
+
+/*
+ * Platform driver
+ */
+
+/* count the number of awaited sub devices */
+static int dove_subdev_cnt(void)
+{
+ struct device_node *np;
+ unsigned int n;
+ static struct of_device_id dove_of_subdev[] = {
+ { .compatible = "marvell,dove-lcd" },
+ { .compatible = "marvell,dove-dcon" },
+ { },
+ };
+
+ n = 0;
+ np = NULL;
+ for (;;) {
+ np = of_find_matching_node_and_match(np,
+ dove_of_subdev, NULL);
+ if (!np)
+ break;
+ if (of_device_is_available(np))
+ n++;
+ }
+ return n;
+}
+
+int dove_probed(void)
+{
+ if (atomic_add_return(1, &probed) == 0)
+ return drm_platform_init(&dove_driver, g_pdev);
+ return 0;
+}
+
+static int dove_pdev_probe(struct platform_device *pdev)
+{
+ int awaited;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ g_pdev = pdev;
+
+ awaited = dove_subdev_cnt();
+ if (awaited == 0) {
+ dev_err(&pdev->dev, "no lcd nor dcon devices\n");
+ return -ENXIO;
+ }
+ if (atomic_sub_return(awaited, &probed) == 0)
+ return drm_platform_init(&dove_driver, pdev);
+ return 0;
+}
+
+static int dove_pdev_remove(struct platform_device *pdev)
+{
+ drm_platform_exit(&dove_driver, pdev);
+ return 0;
+}
+
+static struct of_device_id dove_of_match[] = {
+ { .compatible = "marvell,dove-video" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, dove_of_match);
+
+static struct platform_driver dove_platform_driver = {
+ .probe = dove_pdev_probe,
+ .remove = dove_pdev_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "dove-drm",
+ .pm = &dove_pm_ops,
+ .of_match_table = dove_of_match,
+ },
+};
+
+static int __init dove_drm_init(void)
+{
+ int ret;
+
+ /* wait for other drivers to be loaded (si5351, tda998x..) */
+ msleep(200);
+
+/* uncomment to activate the drm trace at startup time */
+/* drm_debug = DRM_UT_CORE | DRM_UT_DRIVER | DRM_UT_KMS; */
+
+ DRM_DEBUG_DRIVER("\n");
+
+ ret = platform_driver_register(&dove_lcd_platform_driver);
+ if (ret < 0)
+ return ret;
+ ret = platform_driver_register(&dove_dcon_platform_driver);
+ if (ret < 0)
+ goto out1;
+ ret = platform_driver_register(&dove_platform_driver);
+ if (ret < 0)
+ goto out2;
+ return 0;
+
+out2:
+ platform_driver_unregister(&dove_dcon_platform_driver);
+out1:
+ platform_driver_unregister(&dove_lcd_platform_driver);
+ return ret;
+}
+static void __exit dove_drm_fini(void)
+{
+ platform_driver_unregister(&dove_platform_driver);
+ platform_driver_unregister(&dove_dcon_platform_driver);
+ platform_driver_unregister(&dove_lcd_platform_driver);
+}
+module_init(dove_drm_init);
+module_exit(dove_drm_fini);
+
+MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>");
+MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
+MODULE_DESCRIPTION("Marvell Dove DRM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/dove/dove_drv.h b/drivers/gpu/drm/dove/dove_drv.h
new file mode 100644
index 0000000..7488c7e
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_drv.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DOVE_DRV_H__
+#define __DOVE_DRV_H__
+
+#include <linux/clk.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+/* (not tested) */
+/*#define HANDLE_INTERLACE 1*/
+
+#define MAX_DOVE_LCD 2 /* max number of dove lcd devices */
+#define MAX_CLK 4 /* max number of clocks per crtc */
+
+#define PLANE_GFX 0
+#define PLANE_VID 1
+#define NPLANES 2
+
+struct dove_lcd {
+ void __iomem *mmio;
+ struct device *dev;
+ struct drm_crtc crtc;
+
+ u8 num; /* index in dove_drm */
+ u8 dpms;
+
+#ifdef HANDLE_INTERLACE
+ u8 vblank_enabled;
+ u32 v_sync0;
+ u32 v_sync1;
+#endif
+
+ short clk_src; /* current clock source */
+ struct clk *clk[MAX_CLK];
+
+ int irq;
+ char name[16];
+
+ struct drm_pending_vblank_event *event;
+
+ struct drm_plane planes[NPLANES];
+
+ struct drm_connector connector;
+ struct drm_encoder_slave encoder_slave;
+};
+
+struct dove_drm {
+ struct drm_device *drm;
+ struct dove_lcd *lcds[MAX_DOVE_LCD];
+
+ struct drm_fbdev_cma *fbdev;
+ int probe_defer;
+};
+
+extern struct dove_drm dove_drm;
+int dove_probed(void);
+
+u32 dove_vblank_count(struct drm_device *dev, int crtc);
+int dove_enable_vblank(struct drm_device *dev, int crtc);
+void dove_disable_vblank(struct drm_device *dev, int crtc);
+int dove_lcd_init(struct dove_lcd *dove_lcd);
+void dove_crtc_cancel_page_flip(struct dove_lcd *dove_lcd,
+ struct drm_file *file);
+void dove_crtc_start(struct dove_lcd *dove_lcd);
+void dove_crtc_stop(struct dove_lcd *dove_lcd);
+#ifdef CONFIG_DEBUG_FS
+int dove_debugfs_init(struct drm_minor *minor);
+void dove_debugfs_cleanup(struct drm_minor *minor);
+#endif
+extern struct platform_driver dove_lcd_platform_driver;
+
+int dove_ec_probe(struct dove_lcd *dove_lcd);
+int dove_ec_init(struct dove_lcd *dove_lcd);
+extern struct platform_driver dove_dcon_platform_driver;
+#endif /* __DOVE_DRV_H__ */
diff --git a/drivers/gpu/drm/dove/dove_ec.c b/drivers/gpu/drm/dove/dove_ec.c
new file mode 100644
index 0000000..003b031
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_ec.c
@@ -0,0 +1,570 @@
+/*
+ * Marvell Dove DRM driver - encoder / connector and display controller
+ *
+ * Copyright (C) 2013
+ * Jean-Francois Moine <moinejf@free.fr>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/i2c.h>
+#include <linux/of_i2c.h>
+#include <linux/module.h>
+
+#include "dove_drv.h"
+#include "dove_dcon.h"
+
+struct dove_dcon {
+ void __iomem *mmio;
+ struct device *dev;
+};
+static struct dove_dcon dove_dcon;
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+/* LVDS and VGA/DAC functions */
+static void dove_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+static bool dove_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+static void dove_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+static void dove_encoder_commit(struct drm_encoder *encoder)
+{
+}
+static void dove_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static const struct drm_encoder_helper_funcs lvds_encoder_helper_funcs = {
+ .dpms = dove_encoder_dpms,
+ .mode_fixup = dove_encoder_mode_fixup,
+ .prepare = dove_encoder_prepare,
+ .commit = dove_encoder_commit,
+ .mode_set = dove_encoder_mode_set,
+};
+
+/* HDMI (i2c) functions */
+static const struct drm_encoder_helper_funcs hdmi_encoder_helper_funcs = {
+ .dpms = drm_i2c_encoder_dpms,
+ .mode_fixup = drm_i2c_encoder_mode_fixup,
+ .prepare = drm_i2c_encoder_prepare,
+ .commit = drm_i2c_encoder_commit,
+ .mode_set = drm_i2c_encoder_mode_set,
+};
+
+static void dove_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
+ struct i2c_client *i2c_client;
+ struct module *module;
+
+ if (encoder_slave->slave_funcs)
+ encoder_slave->slave_funcs->destroy(encoder);
+ i2c_client = encoder_slave->bus_priv;
+ if (i2c_client) {
+ module = i2c_client->driver->driver.owner;
+ module_put(module);
+ }
+ if (encoder->dev)
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs encoder_funcs = {
+ .destroy = dove_drm_encoder_destroy,
+};
+
+static int dove_encoder_get_hdmi(struct dove_lcd *dove_lcd)
+{
+ struct device *dev = dove_lcd->dev;
+ struct drm_device *drm = dove_drm.drm;
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+ struct drm_encoder *encoder = &encoder_slave->base;
+ struct drm_connector *connector = &dove_lcd->connector;
+ struct i2c_client *i2c_client;
+ struct module *module;
+ struct drm_i2c_encoder_driver *encoder_drv;
+ int ret;
+
+ i2c_client = encoder_slave->bus_priv;
+ if (!i2c_client) {
+ dev_err(dev, "no external-encoder for hdmi\n");
+ return -EINVAL;
+ }
+
+ encoder_drv = to_drm_i2c_encoder_driver(i2c_client->driver);
+ if (!encoder_drv || !encoder_drv->encoder_init) {
+ dev_err(dev, "no external encoder init\n");
+ return -EINVAL;
+ }
+
+ /* lock the external encoder module */
+ module = i2c_client->driver->driver.owner;
+ if (!module || !try_module_get(module)) {
+ dev_err(dev, "cannot get module %s\n", module->name);
+ return -EINVAL;
+ }
+
+ ret = encoder_drv->encoder_init(i2c_client, drm, encoder_slave);
+ if (ret < 0) {
+ dev_err(dev, "slave encoder init failed\n");
+ return ret;
+ }
+ encoder_slave->slave_funcs->create_resources(encoder, connector);
+ return ret;
+}
+
+static int dove_encoder_init(struct dove_lcd *dove_lcd,
+ int mode_encoder)
+{
+ struct drm_device *drm = dove_drm.drm;
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+ struct drm_encoder *encoder = &encoder_slave->base;
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /* do early init in case of error */
+ ret = drm_encoder_init(drm, encoder, &encoder_funcs, mode_encoder);
+ if (ret < 0) {
+ dev_err(dove_lcd->dev, "drm encoder init failed\n");
+ return ret;
+ }
+
+ encoder->possible_crtcs = 1 << dove_lcd->num;
+
+ /*
+ * If the display controller is present,
+ * - the port A cannot be VGA/DAC,
+ * - the port B can be only VGA/DAC and may receive the lcd 0 output.
+ */
+ if (dove_dcon.mmio) {
+ if (dove_lcd->num == 0) {
+ if (mode_encoder == DRM_MODE_ENCODER_DAC) {
+ dev_err(dove_lcd->dev,
+ "bad lcd 0 port-type\n");
+ return -EINVAL;
+ }
+ } else {
+ if (mode_encoder != DRM_MODE_ENCODER_DAC) {
+ dev_err(dove_lcd->dev,
+ "bad lcd 1 port-type\n");
+ return -EINVAL;
+ }
+ encoder->possible_crtcs |= 1;
+
+ /* the port B may receive the LCD 0 output */
+ encoder->possible_clones = 1;
+ }
+ }
+
+ switch (mode_encoder) {
+ case DRM_MODE_ENCODER_DAC:
+/*fixme: to do */
+ case DRM_MODE_ENCODER_LVDS:
+ drm_encoder_helper_add(encoder, &lvds_encoder_helper_funcs);
+ ret = 0;
+ break;
+ case DRM_MODE_ENCODER_TMDS:
+ drm_encoder_helper_add(encoder, &hdmi_encoder_helper_funcs);
+ ret = dove_encoder_get_hdmi(dove_lcd);
+ break;
+ }
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Connector
+ */
+
+static int dove_lvds_get_modes(struct dove_lcd *dove_lcd)
+{
+ struct device *dev = dove_lcd->dev;
+ struct device_node *np = dev->of_node;
+ struct drm_connector *connector = &dove_lcd->connector;
+ struct drm_display_mode *mode;
+ int clock, hdisplay, vdisplay, hfp, hbp, vfp, vbp, hs, vs;
+ int w_mm, h_mm;
+ int ret;
+
+ /* same as of_videomode, but simpler! */
+ np = of_find_node_by_name(np, "display-timings");
+ if (!np) {
+ dev_err(dev, "no display-timings\n");
+ return -EINVAL;
+ }
+ np = of_get_next_child(np, NULL);
+ if (!np) {
+ dev_err(dev, "no 'mode' subnode in DT\n");
+ return -EINVAL;
+ }
+
+ ret = 0;
+ ret |= of_property_read_u32(np, "hactive", &hdisplay);
+ ret |= of_property_read_u32(np, "vactive", &vdisplay);
+ ret |= of_property_read_u32(np, "hfront-porch", &hfp);
+ ret |= of_property_read_u32(np, "hsync-len", &hs);
+ ret |= of_property_read_u32(np, "hback-porch", &hbp);
+ ret |= of_property_read_u32(np, "vfront-porch", &vfp);
+ ret |= of_property_read_u32(np, "vsync-len", &vs);
+ ret |= of_property_read_u32(np, "vback-porch", &vbp);
+ ret |= of_property_read_u32(np, "clock", &clock);
+ if (ret) {
+ dev_err(dev, "bad display-timings\n");
+ return -EINVAL;
+ }
+ if (clock < 15000 || clock > 150000) {
+ dev_err(dev, "bad clock\n");
+ return -EINVAL;
+ }
+
+ mode = drm_mode_create(dove_drm.drm);
+ if (!mode) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ mode->clock = clock;
+ mode->hdisplay = hdisplay;
+ mode->hsync_start = hdisplay + hfp;
+ mode->hsync_end = mode->hsync_start + hs;
+ mode->htotal = mode->hsync_end + hbp;
+ mode->vdisplay = vdisplay;
+ mode->vsync_start = vdisplay + vfp;
+ mode->vsync_end = mode->vsync_start + vs;
+ mode->vtotal = mode->vsync_end + vbp;
+
+ drm_mode_set_name(mode);
+ mode->vrefresh = drm_mode_vrefresh(mode);
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ /* optional display dimension */
+ ret = of_property_read_u32(np, "width-mm", &w_mm);
+ ret |= of_property_read_u32(np, "height-mm", &h_mm);
+ if (ret >= 0) {
+ connector->display_info.width_mm = w_mm;
+ connector->display_info.height_mm = h_mm;
+ }
+ return 1;
+}
+
+static int dove_drm_connector_get_modes(struct drm_connector *connector)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+ int ret;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+/*fixme:to do */
+ case DRM_MODE_CONNECTOR_LVDS:
+ ret = dove_lvds_get_modes(dove_lcd);
+ break;
+ default:
+/* case DRM_MODE_CONNECTOR_HDMIA: */
+/* case DRM_MODE_CONNECTOR_HDMIB: */
+ ret = encoder_slave->slave_funcs->get_modes(&encoder_slave->base,
+ connector);
+ break;
+ }
+ DRM_DEBUG_DRIVER("-> %d\n", ret);
+ return ret;
+}
+
+static int dove_drm_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+
+ if (!encoder_slave->slave_funcs)
+ return MODE_OK;
+ return encoder_slave->slave_funcs->mode_valid(&encoder_slave->base,
+ mode);
+}
+
+static struct drm_encoder *
+dove_drm_connector_best_encoder(struct drm_connector *connector)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+
+ return &dove_lcd->encoder_slave.base;
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+ .get_modes = dove_drm_connector_get_modes,
+ .mode_valid = dove_drm_connector_mode_valid,
+ .best_encoder = dove_drm_connector_best_encoder,
+};
+
+static void dove_drm_connector_destroy(struct drm_connector *connector)
+{
+ if (!connector->dev)
+ return;
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+dove_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+
+ DRM_DEBUG_DRIVER("\n");
+ if (encoder_slave->slave_funcs)
+ return encoder_slave->slave_funcs->detect(&encoder_slave->base,
+ connector);
+/*fixme: KO with VGA*/
+ return connector_status_connected;
+}
+
+static void dove_drm_connector_dpms(struct drm_connector *connector,
+ int mode)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+ struct drm_encoder *encoder = connector->encoder;
+ struct drm_encoder_slave *encoder_slave = to_encoder_slave(encoder);
+ struct dove_lcd *dove_lcd2 =
+ container_of(encoder_slave, struct dove_lcd, encoder_slave);
+ int modeA, modeB;
+ u32 reg;
+
+ if (mode == dove_lcd->connector.dpms)
+ return;
+
+ /* adjust the port B input */
+ if (dove_dcon.mmio) {
+ reg = readl(dove_dcon.mmio + DCON_CTL0);
+ reg &= ~LCD_Port_B_Select_MASK;
+ if (dove_lcd2 != dove_lcd) {
+ if (dove_lcd->num == 0) {
+ modeA = mode;
+ modeB = dove_lcd2->connector.dpms;
+ } else {
+ modeA = dove_lcd->connector.dpms;
+ modeB = mode;
+ }
+
+ if (modeB == DRM_MODE_DPMS_ON) {
+ if (modeA == DRM_MODE_DPMS_ON)
+ reg |= Port_B_Select_A_copy;
+ else
+ reg |= Port_B_Select_LCD0;
+ }
+ }
+ writel(reg, dove_dcon.mmio + DCON_CTL0);
+ DRM_DEBUG_DRIVER("port B select %08x\n", reg);
+ }
+
+ drm_helper_connector_dpms(connector, mode);
+}
+
+static int dove_connector_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct dove_lcd *dove_lcd =
+ container_of(connector, struct dove_lcd, connector);
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+
+ DRM_DEBUG_DRIVER("\n");
+ if (!encoder_slave->slave_funcs)
+ return 0;
+ return encoder_slave->slave_funcs->set_property(&encoder_slave->base,
+ connector,
+ property,
+ value);
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+ .destroy = dove_drm_connector_destroy,
+ .dpms = dove_drm_connector_dpms,
+ .detect = dove_drm_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = dove_connector_set_property,
+};
+
+/* initialize the couple connector-encoder of a LCD */
+int dove_ec_init(struct dove_lcd *dove_lcd)
+{
+ struct device *dev = dove_lcd->dev;
+ struct device_node *np = dev->of_node;
+ struct drm_device *drm = dove_drm.drm;
+ struct drm_connector *connector = &dove_lcd->connector;
+ struct drm_encoder_slave *encoder_slave = &dove_lcd->encoder_slave;
+ struct drm_encoder *encoder = &encoder_slave->base;
+ u32 port_type;
+ int mode_encoder, ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /* get the port (connector) type */
+ if (of_property_read_u32(np, "marvell,port-type", &port_type)) {
+ dev_err(dev, "no port-type\n");
+ return -EINVAL;
+ }
+ switch (port_type) {
+ case DRM_MODE_CONNECTOR_VGA: /* 1 */
+ mode_encoder = DRM_MODE_ENCODER_DAC;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS: /* 7 */
+ mode_encoder = DRM_MODE_ENCODER_LVDS;
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA: /* 11 */
+ case DRM_MODE_CONNECTOR_HDMIB: /* 12 */
+ mode_encoder = DRM_MODE_ENCODER_TMDS;
+ break;
+ default:
+ dev_err(dev, "bad port type %d\n", port_type);
+ return -EINVAL;
+ }
+
+ ret = drm_connector_init(drm, connector, &connector_funcs, port_type);
+ if (ret < 0)
+ return ret;
+
+ drm_connector_helper_add(connector, &connector_helper_funcs);
+
+#ifdef HANDLE_INTERLACE
+ connector->interlace_allowed = true;
+#endif
+
+ ret = dove_encoder_init(dove_lcd, mode_encoder);
+ if (ret < 0)
+ goto err;
+
+ ret = drm_mode_connector_attach_encoder(connector, encoder);
+ if (ret < 0)
+ goto err;
+
+ connector->encoder = encoder;
+
+ ret = drm_sysfs_connector_add(connector);
+ if (ret < 0)
+ goto err;
+
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ ret = drm_object_property_set_value(&connector->base,
+ drm->mode_config.dpms_property,
+ DRM_MODE_DPMS_OFF);
+ if (ret < 0)
+ goto err;
+ return 0;
+
+err:
+ dev_err(dev, "dove_ec_init err %d\n", ret);
+ dove_drm_encoder_destroy(&encoder_slave->base);
+ drm_connector_cleanup(connector);
+ return ret;
+}
+
+/* at probe time, check the presence of a possible external slave encoder */
+int dove_ec_probe(struct dove_lcd *dove_lcd)
+{
+ struct device *dev = dove_lcd->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *i2c_node;
+ struct i2c_client *i2c_client;
+
+ /* get the optional external encoder */
+ i2c_node = of_parse_phandle(np, "marvell,external-encoder", 0);
+ if (!i2c_node)
+ return 0;
+
+ i2c_client = of_find_i2c_device_by_node(i2c_node);
+ of_node_put(i2c_node);
+ if (!i2c_client) {
+ dev_err(dev, "bad external-encoder\n");
+ return -EINVAL;
+ }
+
+ /* check if the slave-encoder module is initialized */
+ if (!i2c_client->driver) {
+ if (dove_drm.probe_defer) {
+ dev_err(dev, "cannot get the external-encoder\n");
+ return -EINVAL;
+ }
+ dove_drm.probe_defer = 1;
+ return -EPROBE_DEFER;
+ }
+
+ dove_lcd->encoder_slave.bus_priv = i2c_client;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Display controller
+ */
+
+static int dove_dcon_remove(struct platform_device *pdev)
+{
+ dove_dcon.mmio = NULL;
+ return 0;
+}
+
+static int dove_dcon_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *mmio;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get dcon resource\n");
+ return -EINVAL;
+ }
+
+ mmio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mmio)) {
+ dev_err(&pdev->dev, "failed map dcon registers\n");
+ return PTR_ERR(mmio);
+ }
+
+ dove_dcon.mmio = mmio;
+ dove_dcon.dev = &pdev->dev;
+
+ /* init done, try to initialize the drm driver */
+ return dove_probed();
+}
+
+static struct of_device_id dove_dcon_of_match[] = {
+ { .compatible = "marvell,dove-dcon" },
+ { },
+};
+struct platform_driver dove_dcon_platform_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "dove-dcon",
+ .of_match_table = dove_dcon_of_match,
+ },
+ .probe = dove_dcon_probe,
+ .remove = dove_dcon_remove,
+};
diff --git a/drivers/gpu/drm/dove/dove_lcd.h b/drivers/gpu/drm/dove/dove_lcd.h
new file mode 100644
index 0000000..03b198b
--- /dev/null
+++ b/drivers/gpu/drm/dove/dove_lcd.h
@@ -0,0 +1,519 @@
+/*
+ * LCD controller registers of Marvell DOVE
+ *
+ * Copyright (C) 2013
+ * Jean-Francois Moine <moinejf@free.fr>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DOVE_LCD_H_
+#define _DOVE_LCD_H_
+
+/* ------------< LCD register >------------ */
+
+/* Video Frame 0&1 start address registers */
+#define LCD_TV_CONTROL1 0x0084
+#define VSYNC_L_OFFSET(o) ((o) << 20)
+#define VSYNC_L_OFFSET_MASK (0xfff << 20)
+#define HWC32_ENABLE BIT(13)
+#define VSYNC_OFFSET_EN BIT(12)
+#define VSYNC_H_OFFSET(o) (o)
+#define VSYNC_H_OFFSET_MASK 0xfff
+
+/* Video Frame 0&1 start address registers */
+#define LCD_SPU_DMA_START_ADDR_Y0 0x00c0
+#define LCD_SPU_DMA_START_ADDR_U0 0x00c4
+#define LCD_SPU_DMA_START_ADDR_V0 0x00c8
+#define LCD_CFG_DMA_START_ADDR_0 0x00cc /* Cmd address */
+#define LCD_SPU_DMA_START_ADDR_Y1 0x00d0
+#define LCD_SPU_DMA_START_ADDR_U1 0x00d4
+#define LCD_SPU_DMA_START_ADDR_V1 0x00d8
+#define LCD_CFG_DMA_START_ADDR_1 0x00dc /* Cmd address */
+
+/* YC & UV Pitch */
+#define LCD_SPU_DMA_PITCH_YC 0x00e0
+#define LCD_Y_C(y, c) (((c) << 16) | (y))
+#define LCD_SPU_DMA_PITCH_UV 0x00e4
+#define LCD_U_V(u, v) (((v) << 16) | (u))
+
+/* Video Starting Point on Screen Register */
+#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00e8
+
+/* Video Size Register */
+#define LCD_SPU_DMA_HPXL_VLN 0x00ec
+
+/* Video Size After zooming Register */
+#define LCD_SPU_DZM_HPXL_VLN 0x00f0
+
+/* Graphic Frame 0&1 Starting Address Register */
+#define LCD_CFG_GRA_START_ADDR0 0x00f4
+#define LCD_CFG_GRA_START_ADDR1 0x00f8
+
+/* Graphic Frame Pitch */
+#define LCD_CFG_GRA_PITCH 0x00fc
+
+/* Graphic Starting Point on Screen Register */
+#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100
+
+/* Graphic Size Register */
+#define LCD_SPU_GRA_HPXL_VLN 0x0104
+
+/* Graphic Size after Zooming Register */
+#define LCD_SPU_GZM_HPXL_VLN 0x0108
+
+/* HW Cursor Starting Point on Screen Register */
+#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010c
+
+/* HW Cursor Size */
+#define LCD_SPU_HWC_HPXL_VLN 0x0110
+
+/* Total Screen Size Register */
+#define LCD_SPUT_V_H_TOTAL 0x0114
+
+/* Total Screen Active Size Register */
+#define LCD_SPU_V_H_ACTIVE 0x0118
+#define LCD_H_V(h, v) (((v) << 16) | (h))
+#define H_LCD(x) ((x) & 0xffff)
+#define V_LCD(x) (((x) >> 16) & 0xffff)
+
+/* Screen H&V Porch Register */
+#define LCD_SPU_H_PORCH 0x011c
+#define LCD_SPU_V_PORCH 0x0120
+#define LCD_F_B(f, b) (((b) << 16) | (f))
+#define F_LCD(x) ((x) & 0xffff)
+#define B_LCD(x) (((x) >> 16) & 0xffff)
+
+/* Screen Blank Color Register */
+#define LCD_SPU_BLANKCOLOR 0x0124
+
+/* HW Cursor Color 1&2 Register */
+#define LCD_SPU_ALPHA_COLOR1 0x0128
+#define HWC32_CFG_ALPHA(alpha) ((alpha) << 24)
+#define LCD_SPU_ALPHA_COLOR2 0x012c
+#define COLOR_MASK 0x00ffffff
+#define COLOR_RGB(r, g, b) (((b) << 16) | ((g) << 8) | (r))
+
+/* Video YUV Color Key Control */
+#define LCD_SPU_COLORKEY_Y 0x0130
+#define CFG_CKEY_Y2(y2) ((y2) << 24)
+#define CFG_CKEY_Y2_MASK 0xff000000
+#define CFG_CKEY_Y1(y1) ((y1) << 16)
+#define CFG_CKEY_Y1_MASK 0x00ff0000
+#define CFG_CKEY_Y(y) ((y) << 8)
+#define CFG_CKEY_Y_MASK 0x0000ff00
+#define CFG_ALPHA_Y(y) (y)
+#define CFG_ALPHA_Y_MASK 0x000000ff
+#define LCD_SPU_COLORKEY_U 0x0134
+#define CFG_CKEY_U2(u2) ((u2) << 24)
+#define CFG_CKEY_U2_MASK 0xff000000
+#define CFG_CKEY_U1(u1) ((u1) << 16)
+#define CFG_CKEY_U1_MASK 0x00ff0000
+#define CFG_CKEY_U(u) ((u) << 8)
+#define CFG_CKEY_U_MASK 0x0000ff00
+#define CFG_ALPHA_U(u) (u)
+#define CFG_ALPHA_U_MASK 0x000000ff
+#define LCD_SPU_COLORKEY_V 0x0138
+#define CFG_CKEY_V2(v2) ((v2) << 24)
+#define CFG_CKEY_V2_MASK 0xff000000
+#define CFG_CKEY_V1(v1) ((v1) << 16)
+#define CFG_CKEY_V1_MASK 0x00ff0000
+#define CFG_CKEY_V(v) ((v) << 8)
+#define CFG_CKEY_V_MASK 0x0000ff00
+#define CFG_ALPHA_V(v) (v)
+#define CFG_ALPHA_V_MASK 0x000000ff
+
+/* LCD General Configuration Register */
+#define LCD_CFG_RDREG4F 0x013c
+#define LCD_SRAM_WAIT BIT(11)
+#define DMA_WATERMARK_MASK 0xff
+#define DMA_WATERMARK(m) (m)
+
+/* SPI Read Data Register */
+#define LCD_SPU_SPI_RXDATA 0x0140
+
+/* Smart Panel Read Data Register */
+#define LCD_SPU_ISA_RSDATA 0x0144
+#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000ff
+#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000ff00
+#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00ff0000
+#define ISA_RXDATA_16BIT_4_DATA_MASK 0xff000000
+#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00ffffff
+
+/* HWC SRAM Read Data Register */
+#define LCD_SPU_HWC_RDDAT 0x0158
+
+/* Gamma Table SRAM Read Data Register */
+#define LCD_SPU_GAMMA_RDDAT 0x015c
+#define GAMMA_RDDAT_MASK 0x000000ff
+
+/* Palette Table SRAM Read Data Register */
+#define LCD_SPU_PALETTE_RDDAT 0x0160
+#define PALETTE_RDDAT_MASK 0x00ffffff
+
+/* I/O Pads Input Read Only Register */
+#define LCD_SPU_IOPAD_IN 0x0178
+#define IOPAD_IN_MASK 0x0fffffff
+
+/* Reserved Read Only Registers */
+#define LCD_CFG_RDREG5F 0x017c
+#define IRE_FRAME_CNT_MASK 0x000000c0
+#define IPE_FRAME_CNT_MASK 0x00000030
+#define GRA_FRAME_CNT_MASK 0x0000000c /* Graphic */
+#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */
+
+/* SPI Control Register. */
+#define LCD_SPU_SPI_CTRL 0x0180
+#define CFG_SCLKCNT(div) ((div) << 24)
+#define CFG_SCLKCNT_MASK 0xff000000
+#define CFG_RXBITS(rx) ((rx) << 16)
+#define CFG_RXBITS_MASK 0x00ff0000
+#define CFG_TXBITS(tx) ((tx) << 8)
+#define CFG_TXBITS_MASK 0x0000ff00
+#define CFG_CLKINV BIT(7)
+#define CFG_KEEPXFER BIT(6)
+#define CFG_RXBITSTO0 BIT(5)
+#define CFG_TXBITSTO0 BIT(4)
+#define CFG_SPI_ENA BIT(3)
+#define CFG_SPI_SEL BIT(2)
+#define CFG_SPI_3W4WB BIT(1)
+#define CFG_SPI_START BIT(0)
+
+/* SPI Tx Data Register */
+#define LCD_SPU_SPI_TXDATA 0x0184
+
+/*
+ * 1. Smart Pannel 8-bit Bus Control Register.
+ * 2. AHB Slave Path Data Port Register
+ */
+#define LCD_SPU_SMPN_CTRL 0x0188
+
+/* DMA Control 0 Register */
+#define LCD_SPU_DMA_CTRL0 0x0190
+#define CFG_NOBLENDING BIT(31)
+#define CFG_GAMMA_ENA BIT(30)
+#define CFG_CBSH_ENA BIT(29)
+#define CFG_PALETTE_ENA BIT(28)
+#define CFG_ARBFAST_ENA BIT(27)
+#define CFG_HWC_1BITMOD BIT(26)
+#define CFG_HWC_1BITENA BIT(25)
+#define CFG_HWC_ENA BIT(24)
+#define CFG_DMAFORMAT(dmaformat) ((dmaformat) << 20)
+#define CFG_DMAFORMAT_MASK 0x00f00000
+#define CFG_GRAFORMAT(graformat) ((graformat) << 16)
+#define CFG_GRAFORMAT_MASK 0x000f0000
+/* for graphic part */
+#define CFG_GRA_FTOGGLE BIT(15)
+#define CFG_GRA_HSMOOTH BIT(14)
+#define CFG_GRA_TSTMODE BIT(13)
+#define CFG_GRA_SWAPRB BIT(12)
+#define CFG_GRA_SWAPUV BIT(11)
+#define CFG_GRA_SWAPYU BIT(10)
+#define CFG_YUV2RGB_GRA BIT(9)
+#define CFG_GRA_ENA BIT(8)
+/* for video part */
+#define CFG_DMA_FTOGGLE BIT(7)
+#define CFG_DMA_HSMOOTH BIT(6)
+#define CFG_DMA_TSTMODE BIT(5)
+#define CFG_DMA_SWAPRB BIT(4)
+#define CFG_DMA_SWAPUV BIT(3)
+#define CFG_DMA_SWAPYU BIT(2)
+#define CFG_DMA_SWAP_MASK 0x0000001c
+#define CFG_YUV2RGB_DMA BIT(1)
+#define CFG_DMA_ENA BIT(0)
+
+/* DMA Control 1 Register */
+#define LCD_SPU_DMA_CTRL1 0x0194
+#define CFG_FRAME_TRIG BIT(31)
+#define CFG_VSYNC_TRIG(trig) ((trig) << 28)
+#define CFG_VSYNC_TRIG_MASK 0x70000000
+#define CFG_VSYNC_INV BIT(27)
+#define CFG_COLOR_KEY_MODE(cmode) ((cmode) << 24)
+#define CFG_COLOR_KEY_MASK 0x07000000
+#define CFG_CARRY BIT(23)
+#define CFG_GATED_ENA BIT(21)
+#define CFG_PWRDN_ENA BIT(20)
+#define CFG_DSCALE(dscale) ((dscale) << 18)
+#define CFG_DSCALE_MASK 0x000c0000
+#define CFG_ALPHA_MODE(amode) ((amode) << 16)
+#define CFG_ALPHA_MODE_MASK 0x00030000
+#define CFG_ALPHA(alpha) ((alpha) << 8)
+#define CFG_ALPHA_MASK 0x0000ff00
+#define CFG_PXLCMD(pxlcmd) (pxlcmd)
+#define CFG_PXLCMD_MASK 0x000000ff
+
+/* SRAM Control Register */
+#define LCD_SPU_SRAM_CTRL 0x0198
+#define CFG_SRAM_INIT_WR_RD(mode) ((mode) << 14)
+#define CFG_SRAM_INIT_WR_RD_MASK 0x0000c000
+#define CFG_SRAM_ADDR_LCDID(id) ((id) << 8)
+#define CFG_SRAM_ADDR_LCDID_MASK 0x00000f00
+#define CFG_SRAM_ADDR(addr) (addr)
+#define CFG_SRAM_ADDR_MASK 0x000000ff
+
+/* SRAM Write Data Register */
+#define LCD_SPU_SRAM_WRDAT 0x019c
+
+/* SRAM RTC/WTC Control Register */
+#define LCD_SPU_SRAM_PARA0 0x01a0
+
+/* SRAM Power Down Control Register */
+#define LCD_SPU_SRAM_PARA1 0x01a4
+#define CFG_CSB_256x32 BIT(15) /* HWC */
+#define CFG_CSB_256x24 BIT(14) /* Palette */
+#define CFG_CSB_256x8 BIT(13) /* Gamma */
+#define CFG_PDWN256x32 BIT(7) /* HWC */
+#define CFG_PDWN256x24 BIT(6) /* Palette */
+#define CFG_PDWN256x8 BIT(5) /* Gamma */
+#define CFG_PDWN32x32 BIT(3)
+#define CFG_PDWN16x66 BIT(2)
+#define CFG_PDWN32x66 BIT(1)
+#define CFG_PDWN64x66 BIT(0)
+
+/* Smart or Dumb Panel Clock Divider */
+#define LCD_CFG_SCLK_DIV 0x01a8
+#define SET_SCLK(src, div, frac) (((src) << 30) | ((frac) << 16 ) | (div))
+
+/* Video Contrast Register */
+#define LCD_SPU_CONTRAST 0x01ac
+#define CFG_BRIGHTNESS(bright) ((bright) << 16)
+#define CFG_BRIGHTNESS_MASK 0xffff0000
+#define CFG_CONTRAST(contrast) (contrast)
+#define CFG_CONTRAST_MASK 0x0000ffff
+
+/* Video Saturation Register */
+#define LCD_SPU_SATURATION 0x01b0
+#define CFG_C_MULTS(mult) ((mult) << 16)
+#define CFG_C_MULTS_MASK 0xffff0000
+#define CFG_SATURATION(sat) (sat)
+#define CFG_SATURATION_MASK 0x0000ffff
+
+/* Video Hue Adjust Register */
+#define LCD_SPU_CBSH_HUE 0x01b4
+#define CFG_SIN0(sin0) ((sin0) << 16)
+#define CFG_SIN0_MASK 0xffff0000
+#define CFG_COS0(con0) (con0)
+#define CFG_COS0_MASK 0x0000ffff
+
+/* Dump LCD Panel Control Register */
+#define LCD_SPU_DUMB_CTRL 0x01b8
+#define CFG_DUMBMODE(mode) ((mode) << 28)
+#define CFG_DUMBMODE_MASK 0xf0000000
+#define CFG_LCDGPIO_O(data) ((data) << 20)
+#define CFG_LCDGPIO_O_MASK 0x0ff00000
+#define CFG_LCDGPIO_ENA(gpio) ((gpio) << 12)
+#define CFG_LCDGPIO_ENA_MASK 0x000ff000
+#define CFG_BIAS_OUT BIT(8)
+#define CFG_REVERSE_RGB BIT(7)
+#define CFG_INV_COMPBLANK BIT(6)
+#define CFG_INV_COMPSYNC BIT(5)
+#define CFG_INV_HENA BIT(4)
+#define CFG_INV_VSYNC BIT(3)
+#define CFG_INV_HSYNC BIT(2)
+#define CFG_INV_PCLK BIT(1)
+#define CFG_DUMB_ENA BIT(0)
+
+/* LCD I/O Pads Control Register */
+#define SPU_IOPAD_CONTROL 0x01bc
+#define CFG_VSC_LINEAR(vm) ((vm) << 18) /* gfx */
+#define CFG_VSC_LINEAR_MASK 0x000c0000
+#define CFG_GRA_VM_ENA BIT(15) /* gfx */
+#define CFG_DMA_VM_ENA BIT(14) /* video */
+#define CFG_CMD_VM_ENA BIT(13)
+#define CFG_CSC(csc) ((csc) << 8)
+#define CFG_CSC_MASK 0x00000300
+#define CFG_AXICTRL(axi) ((axi) << 4)
+#define CFG_AXICTRL_MASK 0x000000f0
+#define CFG_IOPADMODE(iopad) (iopad)
+#define CFG_IOPADMODE_MASK 0x0000000f
+
+/* LCD Interrupt Control Register */
+#define SPU_IRQ_ENA 0x1c0
+/* LCD Interrupt Status Register */
+#define SPU_IRQ_ISR 0x1c4
+#define IRQ_DMA_FRAME0 BIT(31)
+#define IRQ_DMA_FRAME1 BIT(30)
+#define IRQ_DMA_FIFO_UNDERFLOW BIT(29)
+#define IRQ_GRA_FRAME0 BIT(27)
+#define IRQ_GRA_FRAME1 BIT(26)
+#define IRQ_GRA_FIFO_UNDERFLOW BIT(25)
+#define IRQ_SMART_VSYNC BIT(23)
+#define IRQ_DUMB_FRAME_DONE BIT(22)
+#define IRQ_SMART_FRAME_DONE BIT(21)
+#define IRQ_HWCURSOR_FRAME_DONE BIT(20)
+#define IRQ_AHB_CMD_EMPTY BIT(19)
+#define IRQ_SPI_TRANSFER_DONE BIT(18)
+#define IRQ_POWERDOWN BIT(17)
+#define IRQ_AXI_ERROR BIT(16)
+/* read only status */
+#define STA_DMA_FRAME0 BIT(15)
+#define STA_DMA_FRAME1 BIT(14)
+#define STA_DMA_FRAME_COUNT(x) (((x) & (BIT(13) | BIT(12))) >> 12)
+#define STA_GRA_FRAME0 BIT(11)
+#define STA_GRA_FRAME1 BIT(10)
+#define STA_GRA_FRAME_COUNT(x) (((x) & (BIT(9) | BIT(8))) >> 8)
+#define STA_SMART_VSYNC BIT(7)
+#define STA_DUMB_FRAME_DONE BIT(6)
+#define STA_SMART_FRAME_DONE BIT(5)
+#define STA_HWCURSOR_FRAME_DONE BIT(4)
+#define STA_AHB_CMD_EMPTY BIT(3)
+#define STA_DMA_FIFO_EMPTY BIT(2)
+#define STA_GRA_FIFO_EMPTY BIT(1)
+#define STA_POWERDOWN BIT(0)
+
+#define IRQ_DMA_FRAME_DONE (IRQ_DMA_FRAME0 | IRQ_DMA_FRAME1)
+#define IRQ_GRA_FRAME_DONE \
+ (IRQ_GRA_FRAME0 | IRQ_GRA_FRAME1 | IRQ_SMART_VSYNC)
+
+/*
+ * defined Video Memory Color format for DMA control 0 register
+ * DMA0 bit[23:20]
+ */
+#define VMODE_RGB565 0x0
+#define VMODE_RGB1555 0x1
+#define VMODE_RGB888PACKED 0x2
+#define VMODE_RGB888UNPACKED 0x3
+#define VMODE_RGBA888 0x4
+#define VMODE_YUV422PACKED 0x5
+#define VMODE_YUV422PLANAR 0x6
+#define VMODE_YUV420PLANAR 0x7
+#define VMODE_SMPNCMD 0x8
+#define VMODE_PALETTE4BIT 0x9
+#define VMODE_PALETTE8BIT 0xa
+#define VMODE_RESERVED 0xb
+
+/*
+ * defined Graphic Memory Color format for DMA control 0 register
+ * DMA0 bit[19:16]
+ */
+#define GMODE_RGB565 0x0
+#define GMODE_RGB1555 0x1
+#define GMODE_RGB888PACKED 0x2
+#define GMODE_RGB888UNPACKED 0x3
+#define GMODE_RGBA888 0x4
+#define GMODE_YUV422PACKED 0x5
+#define GMODE_YUV422PLANAR 0x6
+#define GMODE_YUV420PLANAR 0x7
+#define GMODE_SMPNCMD 0x8
+#define GMODE_PALETTE4BIT 0x9
+#define GMODE_PALETTE8BIT 0xa
+#define GMODE_RESERVED 0xb
+
+/*
+ * define for DMA control 1 register
+ */
+#define DMA1_FRAME_TRIG 31 /* bit location */
+#define DMA1_VSYNC_MODE 28
+#define DMA1_VSYNC_INV 27
+#define DMA1_CKEY 24
+#define DMA1_CARRY 23
+#define DMA1_LNBUF_ENA 22
+#define DMA1_GATED_ENA 21
+#define DMA1_PWRDN_ENA 20
+#define DMA1_DSCALE 18
+#define DMA1_ALPHA_MODE 16
+#define DMA1_ALPHA 8
+#define DMA1_PXLCMD 0
+
+/*
+ * defined for Configure Dumb Mode
+ * DUMB LCD Panel bit[31:28]
+ */
+#define DUMB16_RGB565_0 0x0
+#define DUMB16_RGB565_1 0x1
+#define DUMB18_RGB666_0 0x2
+#define DUMB18_RGB666_1 0x3
+#define DUMB12_RGB444_0 0x4
+#define DUMB12_RGB444_1 0x5
+#define DUMB24_RGB888_0 0x6
+#define DUMB_BLANK 0x7
+
+/*
+ * defined for Configure I/O Pin Allocation Mode
+ * LCD LCD I/O Pads control register bit[3:0]
+ */
+#define IOPAD_DUMB24 0x0
+#define IOPAD_DUMB18SPI 0x1
+#define IOPAD_DUMB18GPIO 0x2
+#define IOPAD_DUMB16SPI 0x3
+#define IOPAD_DUMB16GPIO 0x4
+#define IOPAD_DUMB12 0x5
+#define IOPAD_SMART18SPI 0x6
+#define IOPAD_SMART16SPI 0x7
+#define IOPAD_SMART8BOTH 0x8
+
+/*
+ * clock source SCLK_Source bit[31:30]
+ */
+#define SCLK_SRC_AXI 0
+#define SCLK_SRC_EXTCLK0 1
+#define SCLK_SRC_PLLDIV 2
+#define SCLK_SRC_EXTCLK1 3
+
+/*
+ * defined Dumb Panel Clock Divider register
+ * SCLK_Source bit[31]
+ */
+#define AXI_BUS_SEL 0x80000000 /* 0: PLL clock select*/
+#define CCD_CLK_SEL 0x40000000
+#define DCON_CLK_SEL 0x20000000
+#define IDLE_CLK_INT_DIV 0x1 /* idle Integer Divider */
+#define DIS_CLK_INT_DIV 0x0 /* Disable Integer Divider */
+
+/* SRAM ID */
+#define SRAMID_GAMMA_YR 0x0
+#define SRAMID_GAMMA_UG 0x1
+#define SRAMID_GAMMA_VB 0x2
+#define SRAMID_PALETTE 0x3
+#define SRAMID_HWC32_RAM1 0xc
+#define SRAMID_HWC32_RAM2 0xd
+#define SRAMID_HWC32_RAM3 0xe
+#define SRAMID_HWC 0xf
+
+/* SRAM INIT Read/Write */
+#define SRAMID_INIT_READ 0x0
+#define SRAMID_INIT_WRITE 0x2
+#define SRAMID_INIT_DEFAULT 0x3
+
+/*
+ * defined VSYNC selection mode for DMA control 1 register
+ * DMA1 bit[30:28]
+ */
+#define VMODE_SMPN 0x0
+#define VMODE_SMPNIRQ 0x1
+#define VMODE_DUMB 0x2
+#define VMODE_IPE 0x3
+#define VMODE_IRE 0x4
+
+/*
+ * defined Configure Alpha and Alpha mode for DMA control 1 register
+ * DMA1 bit[15:08](alpha) / bit[17:16](alpha mode)
+ */
+/* ALPHA mode */
+#define MODE_ALPHA_DMA 0xa0
+#define MODE_ALPHA_GRA 0x1
+#define MODE_ALPHA_CFG 0x2
+
+/* alpha value */
+#define ALPHA_NOGRAPHIC 0xff /* all video, no graphic */
+#define ALPHA_NOVIDEO 0x00 /* all graphic, no video */
+#define ALPHA_GRAPHnVIDEO 0x0f /* Selects graphic & video */
+
+/*
+ * defined Pixel Command for DMA control 1 register
+ * DMA1 bit[07:00]
+ */
+#define PIXEL_CMD 0x81
+
+#endif /* _DOVE_LCD_H_ */
--
Ken ar c'henta? | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
next reply other threads:[~2013-05-16 11:28 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-16 11:28 Jean-Francois Moine [this message]
2013-05-16 11:59 ` [PATCH] ARM: dove: add a kms/drm driver Russell King - ARM Linux
2013-05-16 15:45 ` Jason Cooper
2013-05-16 15:45 ` Jason Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130516132822.09b883cf@armhf \
--to=moinejf@free.fr \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.