rk3288 chromium: drm grafic fb support for x11 mali gpu
authoryzq <yzq@rock-chips.com>
Wed, 26 Mar 2014 03:48:43 +0000 (11:48 +0800)
committeryzq <yzq@rock-chips.com>
Wed, 26 Mar 2014 04:41:08 +0000 (12:41 +0800)
50 files changed:
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/rockchip/Kconfig [new file with mode: 0644]
drivers/gpu/drm/rockchip/Makefile [new file with mode: 0644]
drivers/gpu/drm/rockchip/rk3188_drm_fimd.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rk3188_drm_fimd.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rk3288_drm_fimd.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rk3288_drm_fimd.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_buf.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_buf.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_connector.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_connector.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_core.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_crtc.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_crtc.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_drv.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_drv.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_encoder.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_encoder.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_fb.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_fb.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_gem.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_gem.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_iommu.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_iommu.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_plane.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_plane.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/screen/.gitignore [new file with mode: 0644]
drivers/gpu/drm/rockchip/screen/Kconfig [new file with mode: 0755]
drivers/gpu/drm/rockchip/screen/Makefile [new file with mode: 0644]
drivers/gpu/drm/rockchip/screen/lcd_B080XAN02_mipi.c [new file with mode: 0755]
drivers/gpu/drm/rockchip/screen/lcd_LD089WU1_mipi.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/screen/lcd_general.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/screen/rk_screen.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/transmitter/Kconfig [new file with mode: 0644]
drivers/gpu/drm/rockchip/transmitter/Makefile [new file with mode: 0644]
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.c [new file with mode: 0755]
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.h [new file with mode: 0755]
include/drm/drmP.h
include/drm/rockchip_drm.h [new file with mode: 0644]
include/uapi/drm/rockchip_drm.h [new file with mode: 0644]
include/video/display_timing.h

index b16c50ee769c16cfbf87e9a19e0fc2df8c45c327..35a7b0fb073f1110679f5663e49191ed562c19b2 100644 (file)
@@ -201,6 +201,8 @@ config DRM_SAVAGE
 
 source "drivers/gpu/drm/exynos/Kconfig"
 
+source "drivers/gpu/drm/rockchip/Kconfig"
+
 source "drivers/gpu/drm/vmwgfx/Kconfig"
 
 source "drivers/gpu/drm/gma500/Kconfig"
index 1c9f24396002b31eaa03207b69e0e484646a0549..d7a431945e0bb2f76dc0fa70ca4776ef21251655 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)  +=via/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
+obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
 obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
index 8759d699bd8e1f8aafa88bf0e5682d1c2cf8a1fd..ad4c734259953f85c82108629fbba55de24a9b66 100644 (file)
@@ -3461,7 +3461,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                ret = -ENOSPC;
                goto out;
        }
-
+       fb->pixel_format = crtc->fb->pixel_format;
        if (crtc->fb->pixel_format != fb->pixel_format) {
                DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
                ret = -EINVAL;
index 16f3ec579b3bb2b8448523422634cf3fcdbb70c1..e892bcbe188cfde637ef0002129b10787d37ae74 100644 (file)
@@ -37,7 +37,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_core.h>
 
-unsigned int drm_debug = 0;    /* 1 to enable debug output */
+unsigned int drm_debug = 0xf;  /* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
 unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
new file mode 100644 (file)
index 0000000..3c7efc4
--- /dev/null
@@ -0,0 +1,54 @@
+config DRM_ROCKCHIP
+       tristate "DRM Support for  ROCKCHIP "
+       depends on DRM && ARCH_MULTIPLATFORM
+       select DRM_KMS_HELPER
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
+       help
+         Choose this option if you have a  ROCKCHIP soc chipset.
+         If M is selected the module will be called rockchipdrm.
+
+config DRM_ROCKCHIP_IOMMU
+       bool "ROCKCHIP DRM IOMMU Support"
+       depends on DRM_ROCKCHIP && ARM_DMA_USE_IOMMU
+       help
+         Choose this option if you want to use IOMMU feature for DRM.
+
+config DRM_ROCKCHIP_DMABUF
+       bool "ROCKCHIP DRM DMABUF"
+       depends on DRM_ROCKCHIP
+       help
+         Choose this option if you want to use DMABUF feature for DRM.
+
+config DRM_RK3188_FIMD
+       bool "RK3188 DRM FIMD"
+       depends on OF && DRM_ROCKCHIP 
+       select FB_MODE_HELPERS
+       select VIDEOMODE_HELPERS
+       help
+         Choose this option if you want to use Rockchip FIMD for DRM.
+
+config DRM_RK3288_FIMD
+       bool "RK3288 DRM FIMD"
+       depends on OF && DRM_ROCKCHIP 
+       select FB_MODE_HELPERS
+       select VIDEOMODE_HELPERS
+       help
+         Choose this option if you want to use Rockchip FIMD for DRM.
+
+
+config DRM_ROCKCHIP_HDMI
+       bool "Rockchip DRM HDMI"
+       depends on DRM_ROCKCHIP 
+       help
+         Choose this option if you want to use Rockchip HDMI for DRM.
+
+config DRM_ROCKCHIP_VIDI
+       bool "Rockchip DRM Virtual Display"
+       depends on DRM_ROCKCHIP
+       help
+         Choose this option if you want to use rockchip VIDI for DRM.
+
+source "drivers/gpu/drm/rockchip/screen/Kconfig"
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
new file mode 100644 (file)
index 0000000..ad6e460
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/rockchip
+rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_encoder.o rockchip_drm_connector.o \
+               rockchip_drm_crtc.o rockchip_drm_fbdev.o rockchip_drm_fb.o \
+               rockchip_drm_buf.o rockchip_drm_gem.o rockchip_drm_core.o \
+               rockchip_drm_plane.o
+
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_IOMMU) += rockchip_drm_iommu.o
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_DMABUF) += rockchip_drm_dmabuf.o
+rockchipdrm-$(CONFIG_DRM_RK3188_FIMD)  += rk3188_drm_fimd.o
+rockchipdrm-$(CONFIG_DRM_RK3288_FIMD)  += rk3288_drm_fimd.o
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_HDMI)        += rockchip_hdmi.o rockchip_mixer.o \
+                                          rockchip_ddc.o rockchip_hdmiphy.o \
+                                          rockchip_drm_hdmi.o
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_VIDI)        += rockchip_drm_vidi.o
+
+obj-$(CONFIG_DRM_ROCKCHIP)             += rockchipdrm.o
+obj-y += screen/
+obj-y += transmitter/
diff --git a/drivers/gpu/drm/rockchip/rk3188_drm_fimd.c b/drivers/gpu/drm/rockchip/rk3188_drm_fimd.c
new file mode 100644 (file)
index 0000000..bbcd12a
--- /dev/null
@@ -0,0 +1,1170 @@
+/*
+ * rk3188_drm_fimd.c
+ *
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+
+#include <video/of_display_timing.h>
+#include <drm/rockchip_drm.h>
+#include <linux/rockchip/cpu.h>
+#include <linux/rk_fb.h>
+#include <video/display_timing.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_iommu.h"
+
+/*
+ * FIMD is stand for Fully Interactive Mobile Display and
+ * as a display controller, it transfers contents drawn on memory
+ * to a LCD Panel through Display Interfaces such as RGB or
+ * CPU Interface.
+ */
+
+/* position control register for hardware window 0, 2 ~ 4.*/
+#define VIDOSD_A(win)          (VIDOSD_BASE + 0x00 + (win) * 16)
+#define VIDOSD_B(win)          (VIDOSD_BASE + 0x04 + (win) * 16)
+/*
+ * size control register for hardware windows 0 and alpha control register
+ * for hardware windows 1 ~ 4
+ */
+#define VIDOSD_C(win)          (VIDOSD_BASE + 0x08 + (win) * 16)
+/* size control register for hardware windows 1 ~ 2. */
+#define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
+
+#define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) * 8)
+#define VIDWx_BUF_END(win, buf)                (VIDW_BUF_END(buf) + (win) * 8)
+#define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
+
+/* color key control register for hardware window 1 ~ 4. */
+#define WKEYCON0_BASE(x)               ((WKEYCON0 + 0x140) + ((x - 1) * 8))
+/* color key value register for hardware window 1 ~ 4. */
+#define WKEYCON1_BASE(x)               ((WKEYCON1 + 0x140) + ((x - 1) * 8))
+
+/* FIMD has totally five hardware windows. */
+#define WINDOWS_NR     4
+
+#define get_fimd_context(dev)  platform_get_drvdata(to_platform_device(dev))
+
+struct fimd_driver_data {
+       unsigned int timing_base;
+};
+
+static struct fimd_driver_data rockchip4_fimd_driver_data = {
+       .timing_base = 0x0,
+};
+
+static struct fimd_driver_data rockchip5_fimd_driver_data = {
+       .timing_base = 0x20000,
+};
+
+struct fimd_win_data {
+       unsigned int            offset_x;
+       unsigned int            offset_y;
+       unsigned int            ovl_width;
+       unsigned int            ovl_height;
+       unsigned int            fb_width;
+       unsigned int            fb_height;
+       unsigned int            bpp;
+       dma_addr_t              dma_addr;
+       unsigned int            buf_offsize;
+       unsigned int            line_size;      /* bytes */
+       bool                    enabled;
+       bool                    resume;
+};
+
+struct fimd_context {
+       struct rockchip_drm_subdrv      subdrv;
+       int                             irq;
+       struct drm_crtc                 *crtc;
+       struct clk                      *pd;                            //lcdc power domain
+       struct clk                      *hclk;                          //lcdc AHP clk
+       struct clk                      *dclk;                          //lcdc dclk
+       struct clk                      *aclk;                          //lcdc share memory frequency
+       void __iomem                    *regs;
+       struct fimd_win_data            win_data[WINDOWS_NR];
+       unsigned int                    clkdiv;
+       unsigned int                    default_win;
+       unsigned long                   irq_flags;
+       u32                             vidcon0;
+       u32                             vidcon1;
+       int                             lcdc_id;
+       bool                            suspended;
+       struct mutex                    lock;
+       wait_queue_head_t               wait_vsync_queue;
+       atomic_t                        wait_vsync_event;
+
+       int clkon;
+       void *regsbak;                  //back up reg
+       struct rockchip_drm_panel_info *panel;
+       struct rk_screen *screen;
+};
+
+#include "rk3188_drm_fimd.h"
+static int rk3188_lcdc_get_id(u32 phy_base)
+{
+       if (cpu_is_rk319x()) {
+               if (phy_base == 0xffc40000)
+                       return 0;
+               else if (phy_base == 0xffc50000)
+                       return 1;
+               else
+                       return -EINVAL;
+       } else if (cpu_is_rk3188()) {
+               if (phy_base == 0x1010c000)
+                       return 0;
+               else if (phy_base == 0x1010e000)
+                       return 1;
+               else
+                       return -EINVAL;
+       } else if (cpu_is_rk3026()) {
+               if (phy_base == 0x1010e000)
+                       return 0;
+               else if (phy_base == 0x01110000)
+                       return 1;
+               else
+                       return -EINVAL;
+       } else {
+               pr_err("un supported platform \n");
+               return -EINVAL;
+       }
+
+}
+
+
+static bool fimd_display_is_connected(struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO. */
+
+       return true;
+}
+
+static void *fimd_get_panel(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return ctx->panel;
+}
+
+static int fimd_check_timing(struct device *dev, void *timing)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO. */
+
+       return 0;
+}
+
+static int fimd_display_power_on(struct device *dev, int mode)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO */
+
+       return 0;
+}
+
+static struct rockchip_drm_display_ops fimd_display_ops = {
+       .type = ROCKCHIP_DISPLAY_TYPE_LCD,
+       .is_connected = fimd_display_is_connected,
+       .get_panel = fimd_get_panel,
+       .check_timing = fimd_check_timing,
+       .power_on = fimd_display_power_on,
+};
+
+static void fimd_dpms(struct device *subdrv_dev, int mode)
+{
+       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+       mutex_lock(&ctx->lock);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               /*
+                * enable fimd hardware only if suspended status.
+                *
+                * P.S. fimd_dpms function would be called at booting time so
+                * clk_enable could be called double time.
+                */
+               if (ctx->suspended)
+                       pm_runtime_get_sync(subdrv_dev);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (!ctx->suspended)
+                       pm_runtime_put_sync(subdrv_dev);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
+       }
+
+       mutex_unlock(&ctx->lock);
+}
+
+static void fimd_apply(struct device *subdrv_dev)
+{
+       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+       struct rockchip_drm_manager *mgr = ctx->subdrv.manager;
+       struct rockchip_drm_manager_ops *mgr_ops = mgr->ops;
+       struct rockchip_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
+       struct fimd_win_data *win_data;
+       int i;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
+                       ovl_ops->commit(subdrv_dev, i);
+       }
+
+       if (mgr_ops && mgr_ops->commit)
+               mgr_ops->commit(subdrv_dev);
+}
+
+static void fimd_commit(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct rockchip_drm_panel_info *panel = ctx->panel;
+       struct rk_screen *screen = ctx->screen;
+       u16 right_margin = screen->mode.right_margin;
+       u16 left_margin = screen->mode.left_margin;
+       u16 lower_margin = screen->mode.lower_margin;
+       u16 upper_margin = screen->mode.upper_margin;
+       u16 x_res = screen->mode.xres;
+       u16 y_res = screen->mode.yres;
+       u32 mask, val;
+       int face;
+
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if (ctx->suspended)
+               return;
+
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if(!ctx->clkon)
+               return;
+#if 1
+       switch (screen->face) {
+               case OUT_P565:
+                       face = OUT_P565;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+                       break;
+               case OUT_P666:
+                       face = OUT_P666;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+                       break;
+               case OUT_D888_P565:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+                       break;
+               case OUT_D888_P666:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+                       break;
+               case OUT_P888:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+                       break;
+               default:
+                       printk( "un supported interface!\n");
+                       break;
+       }
+       mask = m_DSP_OUT_FORMAT | m_HSYNC_POL | m_VSYNC_POL |
+               m_DEN_POL | m_DCLK_POL;
+       val = v_DSP_OUT_FORMAT(face) | v_HSYNC_POL(screen->pin_hsync) |
+               v_VSYNC_POL(screen->pin_vsync) | v_DEN_POL(screen->pin_den) |
+               v_DCLK_POL(screen->pin_dclk);
+       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+
+       mask = m_BG_COLOR | m_DSP_BG_SWAP | m_DSP_RB_SWAP |
+               m_DSP_RG_SWAP | m_DSP_DELTA_SWAP |
+               m_DSP_DUMMY_SWAP | m_BLANK_EN;
+       val = v_BG_COLOR(0x000000) | v_DSP_BG_SWAP(screen->swap_gb) |
+               v_DSP_RB_SWAP(screen->swap_rb) | v_DSP_RG_SWAP(screen->
+                               swap_rg) |
+               v_DSP_DELTA_SWAP(screen->
+                               swap_delta) | v_DSP_DUMMY_SWAP(screen->
+                                       swap_dumy) |
+                               v_BLANK_EN(0) | v_BLACK_EN(0);
+       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+       val =
+               v_HSYNC(screen->mode.hsync_len) | v_HORPRD(screen->mode.
+                               hsync_len +
+                               left_margin +
+                               x_res +
+                               right_margin);
+       lcdc_writel(ctx, DSP_HTOTAL_HS_END, val);
+       val = v_HAEP(screen->mode.hsync_len + left_margin + x_res) |
+               v_HASP(screen->mode.hsync_len + left_margin);
+       lcdc_writel(ctx, DSP_HACT_ST_END, val);
+
+       val =
+               v_VSYNC(screen->mode.vsync_len) | v_VERPRD(screen->mode.
+                               vsync_len +
+                               upper_margin +
+                               y_res +
+                               lower_margin);
+       lcdc_writel(ctx, DSP_VTOTAL_VS_END, val);
+
+       val = v_VAEP(screen->mode.vsync_len + upper_margin + y_res) |
+               v_VASP(screen->mode.vsync_len + screen->mode.upper_margin);
+       lcdc_writel(ctx, DSP_VACT_ST_END, val);
+
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+       lcdc_msk_reg(ctx, SYS_CTRL, m_LCDC_STANDBY,
+                       v_LCDC_STANDBY(0));
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+       lcdc_msk_reg(ctx, SYS_CTRL,
+                       m_WIN0_EN | m_WIN1_EN | m_WIN0_RB_SWAP |
+                       m_WIN1_RB_SWAP,
+                       v_WIN0_EN(1) | v_WIN1_EN(0) |
+                       v_WIN0_RB_SWAP(screen->swap_rb) |
+                       v_WIN1_RB_SWAP(screen->swap_rb));
+       lcdc_cfg_done(ctx);
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+#endif
+}
+
+static int fimd_enable_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       u32 val,mask;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ctx->suspended)
+               return -EPERM;
+
+       if (!test_and_set_bit(0, &ctx->irq_flags)) {
+#if 1
+               mask = m_HS_INT_CLEAR | m_HS_INT_EN | m_FS_INT_CLEAR |
+                       m_FS_INT_EN | m_LF_INT_EN | m_LF_INT_CLEAR |
+                       m_LF_INT_NUM | m_BUS_ERR_INT_CLEAR | m_BUS_ERR_INT_EN;
+               val = v_FS_INT_CLEAR(1) | v_FS_INT_EN(1) | v_HS_INT_CLEAR(0) |
+                       v_HS_INT_EN(0) | v_LF_INT_CLEAR(0) | v_LF_INT_EN(0);
+               lcdc_msk_reg(ctx, INT_STATUS, mask, val);
+               lcdc_cfg_done(ctx);
+#endif
+       }
+
+       return 0;
+}
+
+static void fimd_disable_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       u32 val,mask;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ctx->suspended)
+               return;
+
+       if (test_and_clear_bit(0, &ctx->irq_flags)) {
+#if 1
+               lcdc_msk_reg(ctx, INT_STATUS, m_FS_INT_CLEAR,
+                               v_FS_INT_CLEAR(1));
+               mask = m_HS_INT_EN | m_FS_INT_EN | m_LF_INT_EN |
+                       m_BUS_ERR_INT_EN;
+               val = v_HS_INT_EN(0) | v_FS_INT_EN(0) |
+                       v_LF_INT_EN(0) | v_BUS_ERR_INT_EN(0);
+               lcdc_msk_reg(ctx, INT_STATUS, mask, val);
+#endif
+
+       }
+}
+
+static void fimd_wait_for_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       if (ctx->suspended)
+               return;
+
+       atomic_set(&ctx->wait_vsync_event, 1);
+
+       /*
+        * wait for FIMD to signal VSYNC interrupt or return after
+        * timeout which is set to 50ms (refresh rate of 20).
+        */
+       if (!wait_event_timeout(ctx->wait_vsync_queue,
+                               !atomic_read(&ctx->wait_vsync_event),
+                               DRM_HZ/20))
+               DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static struct rockchip_drm_manager_ops fimd_manager_ops = {
+       .dpms = fimd_dpms,
+       .apply = fimd_apply,
+       .commit = fimd_commit,
+       .enable_vblank = fimd_enable_vblank,
+       .disable_vblank = fimd_disable_vblank,
+       .wait_for_vblank = fimd_wait_for_vblank,
+};
+
+static void fimd_win_mode_set(struct device *dev,
+                             struct rockchip_drm_overlay *overlay)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int win;
+       unsigned long offset;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!overlay) {
+               dev_err(dev, "overlay is NULL\n");
+               return;
+       }
+
+       win = overlay->zpos;
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       offset = overlay->fb_x * (overlay->bpp >> 3);
+       offset += overlay->fb_y * overlay->pitch;
+
+       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+
+       win_data = &ctx->win_data[win];
+
+       win_data->offset_x = overlay->crtc_x;
+       win_data->offset_y = overlay->crtc_y;
+       win_data->ovl_width = overlay->crtc_width;
+       win_data->ovl_height = overlay->crtc_height;
+       win_data->fb_width = overlay->fb_width;
+       win_data->fb_height = overlay->fb_height;
+       win_data->dma_addr = overlay->dma_addr[0] + offset;
+       win_data->bpp = overlay->bpp;
+       win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
+                               (overlay->bpp >> 3);
+       win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+
+       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+                       win_data->offset_x, win_data->offset_y);
+       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+                       win_data->ovl_width, win_data->ovl_height);
+       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
+       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+                       overlay->fb_width, overlay->crtc_width);
+}
+
+static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data = &ctx->win_data[win];
+       u8 fmt_cfg = 0;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+       switch(win_data->bpp){
+               case 32:
+                       fmt_cfg = 0;
+                       break;
+               case 24:
+                       fmt_cfg = 1;
+                       break;
+               case 16:
+                       fmt_cfg = 2;
+                       break;
+               default:
+                       printk("not support format %d\n",win_data->bpp);
+                       break;
+       }
+
+
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+       lcdc_msk_reg(ctx , SYS_CTRL, m_WIN0_FORMAT, v_WIN0_FORMAT(fmt_cfg));
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+}
+
+static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+{
+//     struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+}
+
+static void fimd_win_commit(struct device *dev, int zpos)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       struct rk_screen *screen = ctx->screen;
+       int win = zpos;
+       unsigned long val,  size;
+       u32 xpos, ypos;
+
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+
+       if (ctx->suspended)
+               return;
+
+       if (!ctx->clkon)
+               return;
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       win_data = &ctx->win_data[win];
+#if 1
+       /*
+        * SHADOWCON register is used for enabling timing.
+        *
+        * for example, once only width value of a register is set,
+        * if the dma is started then fimd hardware could malfunction so
+        * with protect window setting, the register fields with prefix '_F'
+        * wouldn't be updated at vsync also but updated once unprotect window
+        * is set.
+        */
+       
+       /* buffer end address */
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
+       val = (unsigned long)(win_data->dma_addr + size);
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       printk(KERN_ERR"ctx->regs=%x\n", __func__,__LINE__,ctx->regs);
+       printk(KERN_ERR"-->yzq dma_addr=%x buf_offsize=%x win_data->fb_width=%d \nwin_data->fb_height=%d win_data->ovl_height=%d  win_data->ovl_width=%d \n win_data->offset_x=%d win_data->offset_y=%d win_data->line_size=%d\n win_data->bpp=%d ",win_data->dma_addr,win_data->buf_offsize,win_data->fb_width,win_data->fb_height,win_data->ovl_height, win_data->ovl_width,win_data->offset_x,win_data->offset_y,win_data->line_size,win_data->bpp);
+       xpos = win_data->offset_x + screen->mode.left_margin + screen->mode.hsync_len;
+       ypos = win_data->offset_y + screen->mode.upper_margin + screen->mode.vsync_len;
+
+       lcdc_writel(ctx, WIN0_YRGB_MST0, win_data->dma_addr +win_data->buf_offsize );
+       //lcdc_writel(ctx, WIN0_CBR_MST0, win0->area[0].uv_addr);
+
+//     lcdc_writel(ctx, WIN0_SCL_FACTOR_YRGB,
+//                     v_X_SCL_FACTOR(win0->scale_yrgb_x) |
+//                     v_Y_SCL_FACTOR(win0->scale_yrgb_y));
+//     lcdc_writel(ctx, WIN0_SCL_FACTOR_CBR,
+//                     v_X_SCL_FACTOR(win0->scale_cbcr_x) |
+//                     v_Y_SCL_FACTOR(win0->scale_cbcr_y));
+       lcdc_writel(ctx, WIN0_ACT_INFO, v_ACT_WIDTH(win_data->ovl_width) |
+                       v_ACT_HEIGHT(win_data->ovl_height));
+       lcdc_writel(ctx, WIN0_DSP_ST, v_DSP_STX(xpos) |
+                       v_DSP_STY(ypos));
+       lcdc_writel(ctx, WIN0_DSP_INFO, v_DSP_WIDTH(win_data->fb_width) |
+                       v_DSP_HEIGHT(win_data->fb_height));
+       lcdc_msk_reg(ctx, WIN_VIR, m_WIN0_VIR,
+                       v_WIN0_VIR_VAL(win_data->line_size/(win_data->bpp>>3)));
+       lcdc_cfg_done(ctx);
+
+#if 0
+       /* protect windows */
+       val = readl(ctx->regs + SHADOWCON);
+       val |= SHADOWCON_WINx_PROTECT(win);
+       writel(val, ctx->regs + SHADOWCON);
+
+       /* buffer start address */
+       val = (unsigned long)win_data->dma_addr;
+       writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
+
+
+       DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
+                       (unsigned long)win_data->dma_addr, val, size);
+       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+                       win_data->ovl_width, win_data->ovl_height);
+
+       /* buffer size */
+       val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) |
+               VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size);
+       writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
+
+       /* OSD position */
+       val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
+               VIDOSDxA_TOPLEFT_Y(win_data->offset_y) |
+               VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) |
+               VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y);
+       writel(val, ctx->regs + VIDOSD_A(win));
+
+       last_x = win_data->offset_x + win_data->ovl_width;
+       if (last_x)
+               last_x--;
+       last_y = win_data->offset_y + win_data->ovl_height;
+       if (last_y)
+               last_y--;
+
+       val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y) |
+               VIDOSDxB_BOTRIGHT_X_E(last_x) | VIDOSDxB_BOTRIGHT_Y_E(last_y);
+
+       writel(val, ctx->regs + VIDOSD_B(win));
+
+       DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
+                       win_data->offset_x, win_data->offset_y, last_x, last_y);
+
+       /* hardware window 0 doesn't support alpha channel. */
+       if (win != 0) {
+               /* OSD alpha */
+               alpha = VIDISD14C_ALPHA1_R(0xf) |
+                       VIDISD14C_ALPHA1_G(0xf) |
+                       VIDISD14C_ALPHA1_B(0xf);
+
+               writel(alpha, ctx->regs + VIDOSD_C(win));
+       }
+
+       /* OSD size */
+       if (win != 3 && win != 4) {
+               u32 offset = VIDOSD_D(win);
+               if (win == 0)
+                       offset = VIDOSD_C(win);
+               val = win_data->ovl_width * win_data->ovl_height;
+               writel(val, ctx->regs + offset);
+
+               DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
+       }
+
+       fimd_win_set_pixfmt(dev, win);
+
+       /* hardware window 0 doesn't support color key. */
+       if (win != 0)
+               fimd_win_set_colkey(dev, win);
+
+       /* wincon */
+       val = readl(ctx->regs + WINCON(win));
+       val |= WINCONx_ENWIN;
+       writel(val, ctx->regs + WINCON(win));
+
+       /* Enable DMA channel and unprotect windows */
+       val = readl(ctx->regs + SHADOWCON);
+       val |= SHADOWCON_CHx_ENABLE(win);
+       val &= ~SHADOWCON_WINx_PROTECT(win);
+       writel(val, ctx->regs + SHADOWCON);
+#endif
+#endif
+       win_data->enabled = true;
+
+}
+
+static void fimd_win_disable(struct device *dev, int zpos)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int win = zpos;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       win_data = &ctx->win_data[win];
+
+       if (ctx->suspended) {
+               /* do not resume this window*/
+               win_data->resume = false;
+               return;
+       }
+
+       win_data->enabled = false;
+}
+
+static struct rockchip_drm_overlay_ops fimd_overlay_ops = {
+       .mode_set = fimd_win_mode_set,
+       .commit = fimd_win_commit,
+       .disable = fimd_win_disable,
+};
+
+static struct rockchip_drm_manager fimd_manager = {
+       .pipe           = -1,
+       .ops            = &fimd_manager_ops,
+       .overlay_ops    = &fimd_overlay_ops,
+       .display_ops    = &fimd_display_ops,
+};
+
+static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
+{
+       struct fimd_context *ctx = (struct fimd_context *)dev_id;
+       struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
+       struct drm_device *drm_dev = subdrv->drm_dev;
+       struct rockchip_drm_manager *manager = subdrv->manager;
+       u32 int_reg = lcdc_readl(ctx, INT_STATUS);
+
+       if (int_reg & m_FS_INT_STA) {
+               lcdc_msk_reg(ctx, INT_STATUS, m_FS_INT_CLEAR,
+                            v_FS_INT_CLEAR(1));
+       }
+
+       /* check the crtc is detached already from encoder */
+       if (manager->pipe < 0)
+               goto out;
+
+       drm_handle_vblank(drm_dev, manager->pipe);
+       rockchip_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
+
+       /* set wait vsync event to zero and wake up queue. */
+       if (atomic_read(&ctx->wait_vsync_event)) {
+               atomic_set(&ctx->wait_vsync_event, 0);
+               DRM_WAKEUP(&ctx->wait_vsync_queue);
+       }
+out:
+       return IRQ_HANDLED;
+}
+
+static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = 1, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       drm_dev->irq_enabled = 1;
+
+       /*
+        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       drm_dev->vblank_disable_allowed = 1;
+
+       /* attach this sub driver to iommu mapping if supported. */
+       if (is_drm_iommu_supported(drm_dev))
+               drm_iommu_attach_device(drm_dev, dev);
+
+       return 0;
+}
+
+static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* detach this sub driver from iommu mapping if supported. */
+       if (is_drm_iommu_supported(drm_dev))
+               drm_iommu_detach_device(drm_dev, dev);
+}
+
+
+static void fimd_clear_win(struct fimd_context *ctx, int win)
+{
+       u32 val;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+}
+
+static int fimd_clock(struct fimd_context *ctx, bool enable)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+printk(KERN_ERR"---->yzq %s %d \n",__func__,__LINE__);
+       if (enable) {
+               if(ctx->clkon)
+                       return 0;
+               int ret;
+
+               ret = clk_prepare_enable(ctx->hclk);
+               if (ret < 0)
+                       return ret;
+
+               ret = clk_prepare_enable(ctx->dclk);
+               if (ret < 0)
+                       return ret;
+               
+               ret = clk_prepare_enable(ctx->aclk);
+               if (ret < 0)
+                       return ret;
+               ctx->clkon=1;
+       } else {
+               if(!ctx->clkon)
+                       return 0;
+               clk_disable_unprepare(ctx->aclk);
+               clk_disable_unprepare(ctx->dclk);
+               clk_disable_unprepare(ctx->hclk);
+               ctx->clkon=0;
+       }
+
+       return 0;
+}
+
+static void fimd_window_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int i;
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               win_data->resume = win_data->enabled;
+               fimd_win_disable(dev, i);
+       }
+       fimd_wait_for_vblank(dev);
+}
+
+static void fimd_window_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int i;
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               win_data->enabled = win_data->resume;
+               win_data->resume = false;
+       }
+}
+
+static int fimd_activate(struct fimd_context *ctx, bool enable)
+{
+       struct device *dev = ctx->subdrv.dev;
+       if (enable) {
+               int ret;
+
+               ret = fimd_clock(ctx, true);
+               if (ret < 0)
+                       return ret;
+
+               ctx->suspended = false;
+
+               /* if vblank was enabled status, enable it again. */
+               if (test_and_clear_bit(0, &ctx->irq_flags))
+                       fimd_enable_vblank(dev);
+
+               fimd_window_resume(dev);
+       } else {
+               fimd_window_suspend(dev);
+
+               fimd_clock(ctx, false);
+               ctx->suspended = true;
+       }
+
+       return 0;
+}
+
+int rk_fb_video_mode_from_timing(const struct display_timing *dt, 
+                               struct rk_screen *screen)
+{
+       screen->mode.pixclock = dt->pixelclock.typ;
+       screen->mode.left_margin = dt->hback_porch.typ;
+       screen->mode.right_margin = dt->hfront_porch.typ;
+       screen->mode.xres = dt->hactive.typ;
+       screen->mode.hsync_len = dt->hsync_len.typ;
+       screen->mode.upper_margin = dt->vback_porch.typ;
+       screen->mode.lower_margin = dt->vfront_porch.typ;
+       screen->mode.yres = dt->vactive.typ;
+       screen->mode.vsync_len = dt->vsync_len.typ;
+       screen->type = dt->screen_type;
+       screen->lvds_format = dt->lvds_format;
+       screen->face = dt->face;
+
+       if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+               screen->pin_dclk = 1;
+       else
+               screen->pin_dclk = 0;
+       if(dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+               screen->pin_hsync = 1;
+       else
+               screen->pin_hsync = 0;
+       if(dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+               screen->pin_vsync = 1;
+       else
+               screen->pin_vsync = 0;
+       if(dt->flags & DISPLAY_FLAGS_DE_HIGH)
+               screen->pin_den = 1;
+       else
+               screen->pin_den = 0;
+       
+       return 0;
+       
+}
+
+int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
+{
+       struct display_timings *disp_timing;
+       struct display_timing *dt;
+       disp_timing = of_get_display_timings(np);
+       if (!disp_timing) {
+               pr_err("parse display timing err\n");
+               return -EINVAL;
+       }
+       dt = display_timings_get(disp_timing, 0);
+       rk_fb_video_mode_from_timing(dt, screen);
+       printk(KERN_DEBUG "dclk:%d\n"
+                        "hactive:%d\n"
+                        "hback_porch:%d\n"
+                        "hfront_porch:%d\n"
+                        "hsync_len:%d\n"
+                        "vactive:%d\n"
+                        "vback_porch:%d\n"
+                        "vfront_porch:%d\n"
+                        "vsync_len:%d\n"
+                        "screen_type:%d\n"
+                        "lvds_format:%d\n"
+                        "face:%d\n",
+                       dt->pixelclock.typ,
+                       dt->hactive.typ,
+                       dt->hback_porch.typ,
+                       dt->hfront_porch.typ,
+                       dt->hsync_len.typ,
+                       dt->vactive.typ,
+                       dt->vback_porch.typ,
+                       dt->vfront_porch.typ,
+                       dt->vsync_len.typ,
+                       dt->screen_type,
+                       dt->lvds_format,
+                       dt->face);
+       return 0;
+
+}
+
+static int fimd_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fimd_context *ctx;
+       struct rockchip_drm_subdrv *subdrv;
+       struct rockchip_drm_fimd_pdata *pdata;
+       struct rockchip_drm_panel_info *panel;
+       struct device_node *np = pdev->dev.of_node;
+       struct rk_screen *screen;
+       int prop;
+       int reg_len;
+       struct resource *res;
+       int win;
+       int ret = -EINVAL;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+       of_property_read_u32(np, "rockchip,prop", &prop);
+       if (prop == EXTEND) {
+               printk("---->%s not support lcdc EXTEND\n");
+                       return 0;
+       }
+       printk("------>yzq dev=%x \n",dev);
+       if (dev->of_node) {
+               printk("------>yzq %s %d \n",__func__,__LINE__);
+               panel = devm_kzalloc(dev, sizeof(struct rockchip_drm_panel_info), GFP_KERNEL);
+               screen = devm_kzalloc(dev, sizeof(struct rk_screen), GFP_KERNEL);
+               rk_fb_get_prmry_screen(screen);
+               memcpy(&panel->timing,&screen->mode,sizeof(struct fb_videomode)); 
+       } else {
+               DRM_ERROR("no platform data specified\n");
+               return -EINVAL;
+       }
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       ctx->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->regs))
+               return PTR_ERR(ctx->regs);
+       reg_len = resource_size(res);
+       ctx->regsbak = devm_kzalloc(dev,reg_len,GFP_KERNEL);
+       ctx->lcdc_id = rk3188_lcdc_get_id(res->start);  
+       ctx->screen = screen;
+       if(ctx->lcdc_id == 0){
+               ctx->hclk = clk_get(NULL, "g_h_lcdc0");
+               ctx->aclk = clk_get(NULL, "aclk_lcdc0");
+               ctx->dclk = clk_get(NULL, "dclk_lcdc0");
+       }else{
+               ctx->hclk = clk_get(NULL, "g_h_lcdc1");
+               ctx->aclk = clk_get(NULL, "aclk_lcdc1");
+               ctx->dclk = clk_get(NULL, "dclk_lcdc1");
+       }
+
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0) {
+               dev_err(dev, "cannot find IRQ for lcdc%d\n",
+                       ctx->lcdc_id);
+               return -ENXIO;
+       }
+       ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
+                                                       0, "drm_fimd", ctx);
+       if (ret) {
+               dev_err(dev, "irq request failed.\n");
+               return ret;
+       }
+
+       ctx->default_win = 0;// pdata->default_win;
+       ctx->panel = panel;
+       DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
+       atomic_set(&ctx->wait_vsync_event, 0);
+
+       subdrv = &ctx->subdrv;
+
+       subdrv->dev = dev;
+       subdrv->manager = &fimd_manager;
+       subdrv->probe = fimd_subdrv_probe;
+       subdrv->remove = fimd_subdrv_remove;
+
+       mutex_init(&ctx->lock);
+
+       platform_set_drvdata(pdev, ctx);
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       
+       ret = clk_set_rate(ctx->dclk, ctx->screen->mode.pixclock);
+       if (ret)
+               printk( "set lcdc%d dclk failed\n", ctx->lcdc_id);
+       
+       fimd_activate(ctx, true);
+
+       memcpy(ctx->regsbak,ctx->regs,reg_len);
+       rockchip_drm_subdrv_register(subdrv);
+
+       return 0;
+}
+
+static int fimd_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fimd_context *ctx = platform_get_drvdata(pdev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_drm_subdrv_unregister(&ctx->subdrv);
+
+       if (ctx->suspended)
+               goto out;
+
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_sync(dev);
+
+out:
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimd_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       /*
+        * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
+        * called here, an error would be returned by that interface
+        * because the usage_count of pm runtime is more than 1.
+        */
+       if (!pm_runtime_suspended(dev))
+               return fimd_activate(ctx, false);
+
+       return 0;
+}
+
+static int fimd_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       /*
+        * if entered to sleep when lcd panel was on, the usage_count
+        * of pm runtime would still be 1 so in this case, fimd driver
+        * should be on directly not drawing on pm runtime interface.
+        */
+       if (!pm_runtime_suspended(dev)) {
+               int ret;
+
+               ret = fimd_activate(ctx, true);
+               if (ret < 0)
+                       return ret;
+
+               /*
+                * in case of dpms on(standby), fimd_apply function will
+                * be called by encoder's dpms callback to update fimd's
+                * registers but in case of sleep wakeup, it's not.
+                * so fimd_apply function should be called at here.
+                */
+               fimd_apply(dev);
+       }
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int fimd_runtime_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return fimd_activate(ctx, false);
+}
+
+static int fimd_runtime_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return fimd_activate(ctx, true);
+}
+#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id rk3188_lcdc_dt_ids[] = {
+       {.compatible = "rockchip,rk3188-lcdc",},
+       {}
+};
+#endif
+
+static const struct dev_pm_ops fimd_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
+       SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
+};
+
+struct platform_driver fimd_driver = {
+       .probe          = fimd_probe,
+       .remove         = fimd_remove,
+       .id_table       = rk3188_lcdc_dt_ids,
+       .driver         = {
+               .name   = "rk3188-lcdc",
+               .owner  = THIS_MODULE,
+               .pm     = &fimd_pm_ops,
+               .of_match_table = of_match_ptr(rk3188_lcdc_dt_ids),
+       },
+};
diff --git a/drivers/gpu/drm/rockchip/rk3188_drm_fimd.h b/drivers/gpu/drm/rockchip/rk3188_drm_fimd.h
new file mode 100644 (file)
index 0000000..88cf743
--- /dev/null
@@ -0,0 +1,386 @@
+/********************************************************************
+**          display output interface supported by rockchip lcdc                       *
+********************************************************************/
+/* */
+#define OUT_P888            0  //24bit screen,connect to lcdc D0~D23
+#define OUT_P666            1  //18bit screen,connect to lcdc D0~D17
+#define OUT_P565            2
+#define OUT_S888x           4
+#define OUT_CCIR656         6
+#define OUT_S888            8
+#define OUT_S888DUMY        12
+#define OUT_RGB_AAA        15
+#define OUT_P16BPP4         24
+#define OUT_D888_P666       0x21       //18bit screen,connect to lcdc D2~D7, D10~D15, D18~D23
+#define OUT_D888_P565       0x22
+
+/*******************register definition**********************/
+
+#define SYS_CTRL               (0x00)
+#define m_WIN0_EN              (1<<0)
+#define m_WIN1_EN              (1<<1)
+#define m_HWC_EN               (1<<2)
+#define m_WIN0_FORMAT          (7<<3)
+#define m_WIN1_FORMAT          (7<<6)
+#define m_HWC_COLOR_MODE       (1<<9)
+#define m_HWC_SIZE             (1<<10)
+#define m_WIN0_3D_EN           (1<<11)
+#define m_WIN0_3D_MODE         (7<<12)
+#define m_WIN0_RB_SWAP         (1<<15)
+#define m_WIN0_ALPHA_SWAP      (1<<16)
+#define m_WIN0_Y8_SWAP         (1<<17)
+#define m_WIN0_UV_SWAP         (1<<18)
+#define m_WIN1_RB_SWAP         (1<<19)
+#define m_WIN1_ALPHA_SWAP      (1<<20)
+#define m_WIN1_BL_SWAP         (1<<21)
+#define m_WIN0_OTSD_DISABLE    (1<<22)
+#define m_WIN1_OTSD_DISABLE    (1<<23)
+#define m_DMA_BURST_LENGTH     (3<<24)
+#define m_HWC_LODAD_EN         (1<<26)
+#define m_WIN1_LUT_EN          (1<<27)
+#define m_DSP_LUT_EN           (1<<28)
+#define m_DMA_STOP             (1<<29)
+#define m_LCDC_STANDBY         (1<<30)
+#define m_AUTO_GATING_EN       (1<<31)
+#define v_WIN0_EN(x)           (((x)&1)<<0)
+#define v_WIN1_EN(x)           (((x)&1)<<1)
+#define v_HWC_EN(x)            (((x)&1)<<2)
+#define v_WIN0_FORMAT(x)       (((x)&7)<<3)
+#define v_WIN1_FORMAT(x)       (((x)&7)<<6)
+#define v_HWC_COLOR_MODE(x)    (((x)&1)<<9)
+#define v_HWC_SIZE(x)          (((x)&1)<<10)
+#define v_WIN0_3D_EN(x)                (((x)&1)<<11)
+#define v_WIN0_3D_MODE(x)      (((x)&7)<<12)
+#define v_WIN0_RB_SWAP(x)      (((x)&1)<<15)
+#define v_WIN0_ALPHA_SWAP(x)   (((x)&1)<<16)
+#define v_WIN0_Y8_SWAP(x)      (((x)&1)<<17)
+#define v_WIN0_UV_SWAP(x)      (((x)&1)<<18)
+#define v_WIN1_RB_SWAP(x)      (((x)&1)<<19)
+#define v_WIN1_ALPHA_SWAP(x)   (((x)&1)<<20)
+#define v_WIN1_BL_SWAP(x)      (((x)&1)<<21)
+#define v_WIN0_OTSD_DISABLE(x) (((x)&1)<<22)
+#define v_WIN1_OTSD_DISABLE(x) (((x)&1)<<23)
+#define v_DMA_BURST_LENGTH(x)  (((x)&3)<<24)
+#define v_HWC_LODAD_EN(x)      (((x)&1)<<26)
+#define v_WIN1_LUT_EN(x)       (((x)&1)<<27)
+#define v_DSP_LUT_EN(x)                (((x)&1)<<28)
+#define v_DMA_STOP(x)          (((x)&1)<<29)
+#define v_LCDC_STANDBY(x)      (((x)&1)<<30)
+#define v_AUTO_GATING_EN(x)    (((x)&1)<<31)
+
+
+#define DSP_CTRL0              (0x04)
+#define m_DSP_OUT_FORMAT       (0x0f<<0)
+#define m_HSYNC_POL            (1<<4)
+#define m_VSYNC_POL            (1<<5)
+#define m_DEN_POL              (1<<6)
+#define m_DCLK_POL             (1<<7)
+#define m_WIN0_TOP             (1<<8)
+#define m_DITHER_UP_EN         (1<<9)
+#define m_DITHER_DOWN_MODE     (1<<10)
+#define m_DITHER_DOWN_EN       (1<<11)
+#define m_INTERLACE_DSP_EN     (1<<12)
+#define m_INTERLACE_POL                (1<<13)
+#define m_WIN0_INTERLACE_EN    (1<<14)
+#define m_WIN1_INTERLACE_EN    (1<<15)
+#define m_WIN0_YRGB_DEFLICK_EN (1<<16)
+#define m_WIN0_CBR_DEFLICK_EN  (1<<17)
+#define m_WIN0_ALPHA_MODE      (1<<18)
+#define m_WIN1_ALPHA_MODE      (1<<19)
+#define m_WIN0_CSC_MODE                (3<<20)
+#define m_WIN1_CSC_MODE                (1<<22)
+#define m_WIN0_YUV_CLIP                (1<<23)
+#define m_DSP_CCIR656_AVG      (1<<24)
+#define m_DCLK_OUTPUT_MODE     (1<<25)
+#define m_DCLK_PHASE_LOCK      (1<<26)
+#define m_DITHER_DOWN_SEL      (3<<27)
+#define m_ALPHA_MODE_SEL0      (1<<29)
+#define m_ALPHA_MODE_SEL1      (1<<30)
+#define m_DIFF_DCLK_EN         (1<<31)
+#define v_DSP_OUT_FORMAT(x)    (((x)&0x0f)<<0)
+#define v_HSYNC_POL(x)         (((x)&1)<<4)
+#define v_VSYNC_POL(x)         (((x)&1)<<5)
+#define v_DEN_POL(x)           (((x)&1)<<6)
+#define v_DCLK_POL(x)          (((x)&1)<<7)
+#define v_WIN0_TOP(x)          (((x)&1)<<8)
+#define v_DITHER_UP_EN(x)      (((x)&1)<<9)
+#define v_DITHER_DOWN_MODE(x)  (((x)&1)<<10)
+#define v_DITHER_DOWN_EN(x)    (((x)&1)<<11)
+#define v_INTERLACE_DSP_EN(x)  (((x)&1)<<12)
+#define v_INTERLACE_POL(x)     (((x)&1)<<13)
+#define v_WIN0_INTERLACE_EN(x) (((x)&1)<<14)
+#define v_WIN1_INTERLACE_EN(x) (((x)&1)<<15)
+#define v_WIN0_YRGB_DEFLICK_EN(x)      (((x)&1)<<16)
+#define v_WIN0_CBR_DEFLICK_EN(x)       (((x)&1)<<17)
+#define v_WIN0_ALPHA_MODE(x)           (((x)&1)<<18)
+#define v_WIN1_ALPHA_MODE(x)           (((x)&1)<<19)
+#define v_WIN0_CSC_MODE(x)             (((x)&3)<<20)
+#define v_WIN1_CSC_MODE(x)             (((x)&1)<<22)
+#define v_WIN0_YUV_CLIP(x)             (((x)&1)<<23)
+#define v_DSP_CCIR656_AVG(x)           (((x)&1)<<24)
+#define v_DCLK_OUTPUT_MODE(x)          (((x)&1)<<25)
+#define v_DCLK_PHASE_LOCK(x)           (((x)&1)<<26)
+#define v_DITHER_DOWN_SEL(x)           (((x)&1)<<27)
+#define v_ALPHA_MODE_SEL0(x)           (((x)&1)<<29)
+#define v_ALPHA_MODE_SEL1(x)           (((x)&1)<<30)
+#define v_DIFF_DCLK_EN(x)              (((x)&1)<<31)
+
+
+#define DSP_CTRL1              (0x08)
+#define m_BG_COLOR             (0xffffff<<0)
+#define m_BG_B                 (0xff<<0)
+#define m_BG_G                 (0xff<<8)
+#define m_BG_R                 (0xff<<16)
+#define m_BLANK_EN             (1<<24)
+#define m_BLACK_EN             (1<<25)
+#define m_DSP_BG_SWAP          (1<<26)
+#define m_DSP_RB_SWAP          (1<<27)
+#define m_DSP_RG_SWAP          (1<<28)
+#define m_DSP_DELTA_SWAP       (1<<29)
+#define m_DSP_DUMMY_SWAP       (1<<30)
+#define m_DSP_OUT_ZERO         (1<<31)
+#define v_BG_COLOR(x)          (((x)&0xffffff)<<0)
+#define v_BG_B(x)              (((x)&0xff)<<0)
+#define v_BG_G(x)              (((x)&0xff)<<8)
+#define v_BG_R(x)              (((x)&0xff)<<16)
+#define v_BLANK_EN(x)          (((x)&1)<<24)
+#define v_BLACK_EN(x)          (((x)&1)<<25)
+#define v_DSP_BG_SWAP(x)       (((x)&1)<<26)
+#define v_DSP_RB_SWAP(x)       (((x)&1)<<27)
+#define v_DSP_RG_SWAP(x)       (((x)&1)<<28)
+#define v_DSP_DELTA_SWAP(x)    (((x)&1)<<29)
+#define v_DSP_DUMMY_SWAP(x)    (((x)&1)<<30)
+#define v_DSP_OUT_ZERO(x)      (((x)&1)<<31)
+
+
+#define MCU_CTRL               (0x0c)
+#define m_MCU_PIX_TOTAL                (0x3f<<0)
+#define m_MCU_CS_ST            (0x0f<<6)
+#define m_MCU_CS_END           (0x3f<<10)
+#define m_MCU_RW_ST            (0x0f<<16)
+#define m_MCU_RW_END           (0x3f<<20)
+#define m_MCU_CLK_SEL          (1<<26)
+#define m_MCU_HOLD_MODE                (1<<27)
+#define m_MCU_FS_HOLD_STA      (1<<28)
+#define m_MCU_RS_SELECT                (1<<29)
+#define m_MCU_BYPASS           (1<<30)
+#define m_MCU_TYPE             (1<<31)
+
+#define v_MCU_PIX_TOTAL(x)             (((x)&0x3f)<<0)
+#define v_MCU_CS_ST(x)                 (((x)&0x0f)<<6)
+#define v_MCU_CS_END(x)                        (((x)&0x3f)<<10)
+#define v_MCU_RW_ST(x)                 (((x)&0x0f)<<16)
+#define v_MCU_RW_END(x)                        (((x)&0x3f)<<20)
+#define v_MCU_CLK_SEL(x)               (((x)&1)<<26)
+#define v_MCU_HOLD_MODE(x)             (((x)&1)<<27)
+#define v_MCU_FS_HOLD_STA(x)           (((x)&1)<<28)
+#define v_MCU_RS_SELECT(x)             (((x)&1)<<29)
+#define v_MCU_BYPASS(x)                (((x)&1)<<30)
+#define v_MCU_TYPE(x)                  (((x)&1)<<31)
+
+#define INT_STATUS             (0x10)
+#define m_HS_INT_STA           (1<<0)  //status
+#define m_FS_INT_STA           (1<<1)
+#define m_LF_INT_STA           (1<<2)
+#define m_BUS_ERR_INT_STA      (1<<3)
+#define m_HS_INT_EN            (1<<4)  //enable
+#define m_FS_INT_EN            (1<<5)
+#define m_LF_INT_EN            (1<<6)
+#define m_BUS_ERR_INT_EN       (1<<7)
+#define m_HS_INT_CLEAR         (1<<8) //auto clear
+#define m_FS_INT_CLEAR         (1<<9)
+#define m_LF_INT_CLEAR         (1<<10)
+#define m_BUS_ERR_INT_CLEAR    (1<<11)
+#define m_LF_INT_NUM           (0xfff<<12)
+#define v_HS_INT_EN(x)         (((x)&1)<<4)
+#define v_FS_INT_EN(x)         (((x)&1)<<5)
+#define v_LF_INT_EN(x)         (((x)&1)<<6)
+#define v_BUS_ERR_INT_EN(x)    (((x)&1)<<7)
+#define v_HS_INT_CLEAR(x)      (((x)&1)<<8)
+#define v_FS_INT_CLEAR(x)      (((x)&1)<<9)
+#define v_LF_INT_CLEAR(x)      (((x)&1)<<10)
+#define v_BUS_ERR_INT_CLEAR(x) (((x)&1)<<11)
+#define v_LF_INT_NUM(x)                (((x)&0xfff)<<12)
+
+
+#define ALPHA_CTRL             (0x14)
+#define m_WIN0_ALPHA_EN                (1<<0)
+#define m_WIN1_ALPHA_EN                (1<<1)
+#define m_HWC_ALPAH_EN         (1<<2)
+#define m_WIN0_ALPHA_VAL       (0xff<<4)
+#define m_WIN1_ALPHA_VAL       (0xff<<12)
+#define m_HWC_ALPAH_VAL                (0x0f<<20)
+#define v_WIN0_ALPHA_EN(x)     (((x)&1)<<0)
+#define v_WIN1_ALPHA_EN(x)     (((x)&1)<<1)
+#define v_HWC_ALPAH_EN(x)      (((x)&1)<<2)
+#define v_WIN0_ALPHA_VAL(x)    (((x)&0xff)<<4)
+#define v_WIN1_ALPHA_VAL(x)    (((x)&0xff)<<12)
+#define v_HWC_ALPAH_VAL(x)     (((x)&0x0f)<<20)
+
+#define WIN0_COLOR_KEY         (0x18)
+#define m_COLOR_KEY_VAL                (0xffffff<<0)
+#define m_COLOR_KEY_EN         (1<<24)
+#define v_COLOR_KEY_VAL(x)     (((x)&0xffffff)<<0)
+#define v_COLOR_KEY_EN(x)      (((x)&1)<<24)
+
+#define WIN1_COLOR_KEY         (0x1C)
+
+
+#define WIN0_YRGB_MST0         (0x20)
+#define WIN0_CBR_MST0          (0x24)
+#define WIN0_YRGB_MST1         (0x28)
+#define WIN0_CBR_MST1          (0x2C)
+#define WIN_VIR                        (0x30)
+#define m_WIN0_VIR             (0x1fff << 0)
+#define m_WIN1_VIR             (0x1fff << 16)
+#define v_WIN0_VIR_VAL(x)       ((x)<<0)
+#define v_WIN1_VIR_VAL(x)       ((x)<<16)
+#define v_ARGB888_VIRWIDTH(x)  (((x)&0x1fff)<<0)
+#define v_RGB888_VIRWIDTH(x)   (((((x*3)>>2)+((x)%3))&0x1fff)<<0)
+#define v_RGB565_VIRWIDTH(x)    ((DIV_ROUND_UP(x,2)&0x1fff)<<0)
+#define v_YUV_VIRWIDTH(x)       ((DIV_ROUND_UP(x,4)&0x1fff)<<0)
+#define v_WIN1_ARGB888_VIRWIDTH(x)     (((x)&0x1fff)<<16)
+#define v_WIN1_RGB888_VIRWIDTH(x)      (((((x*3)>>2)+((x)%3))&0x1fff)<<16)
+#define v_WIN1_RGB565_VIRWIDTH(x)       ((DIV_ROUND_UP(x,2)&0x1fff)<<16)
+
+
+
+#define WIN0_ACT_INFO          (0x34)
+#define m_ACT_WIDTH            (0x1fff<<0)
+#define m_ACT_HEIGHT           (0x1fff<<16)
+#define v_ACT_WIDTH(x)         (((x-1)&0x1fff)<<0)
+#define v_ACT_HEIGHT(x)        (((x-1)&0x1fff)<<16)
+
+#define WIN0_DSP_INFO          (0x38)
+#define v_DSP_WIDTH(x)         (((x-1)&0x7ff)<<0)
+#define v_DSP_HEIGHT(x)        (((x-1)&0x7ff)<<16)
+
+#define WIN0_DSP_ST            (0x3C)
+#define v_DSP_STX(x)           (((x)&0xfff)<<0)
+#define v_DSP_STY(x)           (((x)&0xfff)<<16)
+
+#define WIN0_SCL_FACTOR_YRGB   (0x40)
+#define v_X_SCL_FACTOR(x)  (((x)&0xffff)<<0)
+#define v_Y_SCL_FACTOR(x)  (((x)&0xffff)<<16)
+
+#define WIN0_SCL_FACTOR_CBR    (0x44)
+#define WIN0_SCL_OFFSET                (0x48)
+#define WIN1_MST               (0x4C)
+#define WIN1_DSP_INFO          (0x50)
+#define WIN1_DSP_ST            (0x54)
+#define HWC_MST                        (0x58)
+#define HWC_DSP_ST             (0x5C)
+#define HWC_COLOR_LUT0         (0x60)
+#define HWC_COLOR_LUT1         (0x64)
+#define HWC_COLOR_LUT2         (0x68)
+#define DSP_HTOTAL_HS_END      (0x6C)
+#define v_HSYNC(x)             (((x)&0xfff)<<0)   //hsync pulse width
+#define v_HORPRD(x)            (((x)&0xfff)<<16)   //horizontal period
+
+#define DSP_HACT_ST_END                (0x70)
+#define v_HAEP(x)              (((x)&0xfff)<<0)  //horizontal active end point
+#define v_HASP(x)              (((x)&0xfff)<<16) //horizontal active start point
+
+#define DSP_VTOTAL_VS_END      (0x74)
+#define v_VSYNC(x)             (((x)&0xfff)<<0)
+#define v_VERPRD(x)            (((x)&0xfff)<<16)
+#define DSP_VACT_ST_END                (0x78)
+#define v_VAEP(x)              (((x)&0xfff)<<0)
+#define v_VASP(x)              (((x)&0xfff)<<16)
+
+#define DSP_VS_ST_END_F1       (0x7C)
+#define DSP_VACT_ST_END_F1     (0x80)
+#define REG_CFG_DONE           (0x90)
+#define MCU_BYPASS_WPORT       (0x100)
+#define MCU_BYPASS_RPORT       (0x200)
+#define WIN1_LUT_ADDR          (0x400)
+#define DSP_LUT_ADDR           (0x800)
+
+/*
+       RK3026/RK3028A max output  resolution 1920x1080
+       support IEP instead of  3d
+*/
+//#ifdef CONFIG_ARCH_RK3026
+//SYS_CTRL 0x00
+#define m_DIRECT_PATCH_EN         (1<<11)
+#define m_DIRECT_PATH_LAY_SEL     (1<<12)
+
+#define v_DIRECT_PATCH_EN(x)      (((x)&1)<<11)
+#define v_DIRECT_PATH_LAY_SEL(x)  (((x)&1)<<12)
+
+//INT_STATUS 0x10
+#define m_WIN0_EMPTY_INTR_EN      (1<<24)
+#define m_WIN1_EMPTY_INTR_EN      (1<<25)
+#define m_WIN0_EMPTY_INTR_CLR     (1<<26)
+#define m_WIN1_EMPTY_INTR_CLR     (1<<27)
+#define m_WIN0_EMPTY_INTR_STA     (1<<28)
+#define m_WIN1_EMPTY_INTR_STA     (1<<29)
+
+#define v_WIN0_EMPTY_INTR_EN(x)   (((x)&1)<<24)
+#define v_WIN1_EMPTY_INTR_EN(x)   (((x)&1)<<25)
+#define v_WIN0_EMPTY_INTR_CLR(x)  (((x)&1)<<26)
+#define v_WIN1_EMPTY_INTR_CLR(x)  (((x)&1)<<27)
+#define v_WIN0_EMPTY_INTR_STA(x)  (((x)&1)<<28)
+#define v_WIN1_EMPTY_INTR_STA(x)  (((x)&1)<<29)
+//#endif
+
+
+#define CalScale(x, y)              ((((u32)(x-1))*0x1000)/(y-1))
+
+static inline void lcdc_writel(struct fimd_context *ctx,u32 offset,u32 v)
+{
+       u32 *_pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);   
+       *_pv = v;
+       writel_relaxed(v,ctx->regs+offset);     
+}
+
+static inline u32 lcdc_readl(struct fimd_context *ctx,u32 offset)
+{
+       u32 v;
+       u32 *_pv = (u32*)ctx->regsbak;
+       _pv += (offset >> 2);
+       v = readl_relaxed(ctx->regs+offset);
+       *_pv = v;
+       return v;
+}
+
+static inline u32 lcdc_read_bit(struct fimd_context *ctx,u32 offset,u32 msk) 
+{
+       u32 _v = readl_relaxed(ctx->regs+offset); 
+       _v &= msk;
+       return (_v >> msk);   
+}
+
+static inline void  lcdc_set_bit(struct fimd_context *ctx,u32 offset,u32 msk) 
+{
+       u32* _pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                           
+       (*_pv) |= msk;                          
+       writel_relaxed(*_pv,ctx->regs + offset); 
+} 
+
+static inline void lcdc_clr_bit(struct fimd_context *ctx,u32 offset,u32 msk)
+{
+       u32* _pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                           
+       (*_pv) &= (~msk);                               
+       writel_relaxed(*_pv,ctx->regs + offset); 
+} 
+
+static inline void  lcdc_msk_reg(struct fimd_context *ctx,u32 offset,u32 msk,u32 v)
+{
+       u32 *_pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                   
+       (*_pv) &= (~msk);                               
+       (*_pv) |= v;                            
+       writel_relaxed(*_pv,ctx->regs+offset);  
+}
+
+static inline void lcdc_cfg_done(struct fimd_context *ctx) 
+{
+       writel_relaxed(0x01,ctx->regs+REG_CFG_DONE); 
+       dsb();  
+} 
+
+
diff --git a/drivers/gpu/drm/rockchip/rk3288_drm_fimd.c b/drivers/gpu/drm/rockchip/rk3288_drm_fimd.c
new file mode 100644 (file)
index 0000000..25eb742
--- /dev/null
@@ -0,0 +1,1480 @@
+/*
+ * rk3288_drm_fimd.c
+ *
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+
+#include <video/of_display_timing.h>
+#include <drm/rockchip_drm.h>
+#include <linux/rockchip/cpu.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rk_fb.h>
+#include <video/display_timing.h>
+#include <linux/rockchip/cpu.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rockchip/grf.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_iommu.h"
+
+/*
+ * FIMD is stand for Fully Interactive Mobile Display and
+ * as a display controller, it transfers contents drawn on memory
+ * to a LCD Panel through Display Interfaces such as RGB or
+ * CPU Interface.
+ */
+
+/* position control register for hardware window 0, 2 ~ 4.*/
+#define VIDOSD_A(win)          (VIDOSD_BASE + 0x00 + (win) * 16)
+#define VIDOSD_B(win)          (VIDOSD_BASE + 0x04 + (win) * 16)
+/*
+ * size control register for hardware windows 0 and alpha control register
+ * for hardware windows 1 ~ 4
+ */
+#define VIDOSD_C(win)          (VIDOSD_BASE + 0x08 + (win) * 16)
+/* size control register for hardware windows 1 ~ 2. */
+#define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
+
+#define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) * 8)
+#define VIDWx_BUF_END(win, buf)                (VIDW_BUF_END(buf) + (win) * 8)
+#define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
+
+/* color key control register for hardware window 1 ~ 4. */
+#define WKEYCON0_BASE(x)               ((WKEYCON0 + 0x140) + ((x - 1) * 8))
+/* color key value register for hardware window 1 ~ 4. */
+#define WKEYCON1_BASE(x)               ((WKEYCON1 + 0x140) + ((x - 1) * 8))
+
+/* FIMD has totally five hardware windows. */
+#define WINDOWS_NR     4
+/*****************************************************************************************************/
+#define SCALE_FACTOR_BILI_DN_FIXPOINT_SHIFT   12   /* 4.12*/
+#define SCALE_FACTOR_BILI_DN_FIXPOINT(x)      ((INT32)((x)*(1 << SCALE_FACTOR_BILI_DN_FIXPOINT_SHIFT)))
+
+#define SCALE_FACTOR_BILI_UP_FIXPOINT_SHIFT   16   /* 0.16*/
+
+#define SCALE_FACTOR_AVRG_FIXPOINT_SHIFT   16   /*0.16*/
+#define SCALE_FACTOR_AVRG_FIXPOINT(x)      ((INT32)((x)*(1 << SCALE_FACTOR_AVRG_FIXPOINT_SHIFT)))
+
+#define SCALE_FACTOR_BIC_FIXPOINT_SHIFT    16   /* 0.16*/
+#define SCALE_FACTOR_BIC_FIXPOINT(x)       ((INT32)((x)*(1 << SCALE_FACTOR_BIC_FIXPOINT_SHIFT)))
+
+#define SCALE_FACTOR_DEFAULT_FIXPOINT_SHIFT    12  /*NONE SCALE,vsd_bil*/
+#define SCALE_FACTOR_VSDBIL_FIXPOINT_SHIFT     12  /*VER SCALE DOWN BIL*/
+
+/*****************************************************************************************************/
+
+/*#define GET_SCALE_FACTOR_BILI(src, dst) ((((src) - 1) << SCALE_FACTOR_BILI_FIXPOINT_SHIFT) / ((dst) - 1))*/
+/*#define GET_SCALE_FACTOR_BIC(src, dst)  ((((src) - 1) << SCALE_FACTOR_BIC_FIXPOINT_SHIFT) / ((dst) - 1))*/
+/*modified by hpz*/
+#define GET_SCALE_FACTOR_BILI_DN(src, dst)  ((((src)*2 - 3) << (SCALE_FACTOR_BILI_DN_FIXPOINT_SHIFT-1)) / ((dst) - 1))
+#define GET_SCALE_FACTOR_BILI_UP(src, dst)  ((((src)*2 - 3) << (SCALE_FACTOR_BILI_UP_FIXPOINT_SHIFT-1)) / ((dst) - 1))
+#define GET_SCALE_FACTOR_BIC(src, dst)      ((((src)*2 - 3) << (SCALE_FACTOR_BIC_FIXPOINT_SHIFT-1)) / ((dst) - 1))
+
+#define get_fimd_context(dev)  platform_get_drvdata(to_platform_device(dev))
+
+static struct rk_fb_trsm_ops *trsm_lvds_ops;
+static struct rk_fb_trsm_ops *trsm_edp_ops;
+static struct rk_fb_trsm_ops *trsm_mipi_ops;
+
+int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
+{
+       switch (type) {
+       case SCREEN_RGB:
+       case SCREEN_LVDS:
+       case SCREEN_DUAL_LVDS:
+               trsm_lvds_ops = ops;
+               break;
+       case SCREEN_EDP:
+               trsm_edp_ops = ops;
+               break;
+       case SCREEN_MIPI:
+       case SCREEN_DUAL_MIPI:
+               trsm_mipi_ops = ops;
+               break;
+       default:
+               printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
+                       __func__, type);
+               break;
+       }
+       return 0;
+}
+struct fimd_driver_data {
+       unsigned int timing_base;
+};
+
+static struct fimd_driver_data rockchip4_fimd_driver_data = {
+       .timing_base = 0x0,
+};
+
+static struct fimd_driver_data rockchip5_fimd_driver_data = {
+       .timing_base = 0x20000,
+};
+
+struct fimd_win_data {
+       unsigned int            offset_x;
+       unsigned int            offset_y;
+       unsigned int            ovl_width;
+       unsigned int            ovl_height;
+       unsigned int            fb_width;
+       unsigned int            fb_height;
+       unsigned int            bpp;
+       dma_addr_t              dma_addr;
+       unsigned int            buf_offsize;
+       unsigned int            line_size;      /* bytes */
+       bool                    enabled;
+       bool                    resume;
+};
+
+struct fimd_context {
+       struct rockchip_drm_subdrv      subdrv;
+       int                             irq;
+       struct drm_crtc                 *crtc;
+       struct clk                      *pd;                            //lcdc power domain
+       struct clk                      *hclk;                          //lcdc AHP clk
+       struct clk                      *dclk;                          //lcdc dclk
+       struct clk                      *aclk;                          //lcdc share memory frequency
+       void __iomem                    *regs;
+       struct fimd_win_data            win_data[WINDOWS_NR];
+       unsigned int                    clkdiv;
+       unsigned int                    default_win;
+       unsigned long                   irq_flags;
+       u32                             vidcon0;
+       u32                             vidcon1;
+       int                             lcdc_id;
+       bool                            suspended;
+       struct mutex                    lock;
+       wait_queue_head_t               wait_vsync_queue;
+       atomic_t                        wait_vsync_event;
+
+       int clkon;
+       void *regsbak;                  //back up reg
+       struct rockchip_drm_panel_info *panel;
+       struct rk_screen *screen;
+};
+
+#include "rk3288_drm_fimd.h"
+static int rk3288_lcdc_get_id(u32 phy_base)
+{
+       if (cpu_is_rk3288()) {
+               if (phy_base == 0xff930000)/*vop big*/
+                       return 0;
+               else if (phy_base == 0xff940000)/*vop lit*/     
+                       return 1;
+               else
+                       return -EINVAL;
+       } else {
+               pr_err("un supported platform \n");
+               return -EINVAL;
+       }
+}
+
+
+static bool fimd_display_is_connected(struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO. */
+
+       return true;
+}
+
+static void *fimd_get_panel(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return ctx->panel;
+}
+
+static int fimd_check_timing(struct device *dev, void *timing)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO. */
+
+       return 0;
+}
+
+static int fimd_display_power_on(struct device *dev, int mode)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO */
+
+       return 0;
+}
+
+static struct rockchip_drm_display_ops fimd_display_ops = {
+       .type = ROCKCHIP_DISPLAY_TYPE_LCD,
+       .is_connected = fimd_display_is_connected,
+       .get_panel = fimd_get_panel,
+       .check_timing = fimd_check_timing,
+       .power_on = fimd_display_power_on,
+};
+
+static void fimd_dpms(struct device *subdrv_dev, int mode)
+{
+       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+       mutex_lock(&ctx->lock);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               /*
+                * enable fimd hardware only if suspended status.
+                *
+                * P.S. fimd_dpms function would be called at booting time so
+                * clk_enable could be called double time.
+                */
+
+               if(trsm_lvds_ops != NULL){
+                       printk(KERN_ERR"------>yzq enable lvds\n");     
+                       trsm_lvds_ops->enable();
+               }
+               if (ctx->suspended)
+                       pm_runtime_get_sync(subdrv_dev);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (!ctx->suspended)
+                       pm_runtime_put_sync(subdrv_dev);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
+       }
+
+       mutex_unlock(&ctx->lock);
+}
+
+static void fimd_apply(struct device *subdrv_dev)
+{
+       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+       struct rockchip_drm_manager *mgr = ctx->subdrv.manager;
+       struct rockchip_drm_manager_ops *mgr_ops = mgr->ops;
+       struct rockchip_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
+       struct fimd_win_data *win_data;
+       int i;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
+                       ovl_ops->commit(subdrv_dev, i);
+       }
+
+       if (mgr_ops && mgr_ops->commit)
+               mgr_ops->commit(subdrv_dev);
+}
+
+static int rk3288_lcdc_alpha_cfg(struct fimd_context *ctx,int win_id)
+{
+       struct alpha_config alpha_config;
+       struct fimd_win_data *win_data;
+       enum alpha_mode alpha_mode;
+       u32 mask, val;
+       int ppixel_alpha,global_alpha;
+       u32 src_alpha_ctl,dst_alpha_ctl;
+       int g_alpha_val=0;
+
+       win_data = &ctx->win_data[win_id];
+       ppixel_alpha = (win_data->bpp==32) ? 1 : 0;
+       global_alpha = 1; 
+       alpha_config.src_global_alpha_val = 1;
+       alpha_mode = AB_SRC_OVER;
+       global_alpha = (g_alpha_val == 0) ? 0 : 1; 
+       alpha_config.src_global_alpha_val = g_alpha_val;
+       /*printk("%s,alpha_mode=%d,alpha_en=%d,ppixel_a=%d,gla_a=%d\n",
+               __func__,win->alpha_mode,win->alpha_en,ppixel_alpha,global_alpha);*/
+       switch(alpha_mode){
+       case AB_USER_DEFINE:
+               break;
+       case AB_CLEAR:
+               alpha_config.src_factor_mode=AA_ZERO;
+               alpha_config.dst_factor_mode=AA_ZERO;           
+               break;
+       case AB_SRC:
+               alpha_config.src_factor_mode=AA_ONE;
+               alpha_config.dst_factor_mode=AA_ZERO;
+               break;
+       case AB_DST:
+               alpha_config.src_factor_mode=AA_ZERO;
+               alpha_config.dst_factor_mode=AA_ONE;
+               break;
+       case AB_SRC_OVER:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_ONE;
+               alpha_config.dst_factor_mode=AA_SRC_INVERSE;            
+               break;
+       case AB_DST_OVER:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC_INVERSE;
+               alpha_config.dst_factor_mode=AA_ONE;
+               break;
+       case AB_SRC_IN:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC;
+               alpha_config.dst_factor_mode=AA_ZERO;
+               break;
+       case AB_DST_IN:
+               alpha_config.src_factor_mode=AA_ZERO;
+               alpha_config.dst_factor_mode=AA_SRC;
+               break;
+       case AB_SRC_OUT:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC_INVERSE;
+               alpha_config.dst_factor_mode=AA_ZERO;           
+               break;
+       case AB_DST_OUT:
+               alpha_config.src_factor_mode=AA_ZERO;
+               alpha_config.dst_factor_mode=AA_SRC_INVERSE;    
+               break;
+       case AB_SRC_ATOP:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC;
+               alpha_config.dst_factor_mode=AA_SRC_INVERSE;            
+               break;
+       case AB_DST_ATOP:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC_INVERSE;
+               alpha_config.dst_factor_mode=AA_SRC;            
+               break;
+       case XOR:
+               alpha_config.src_color_mode=AA_SRC_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC_INVERSE;
+               alpha_config.dst_factor_mode=AA_SRC_INVERSE;                    
+               break;  
+       case AB_SRC_OVER_GLOBAL:        
+               alpha_config.src_global_alpha_mode=AA_PER_PIX_GLOBAL;
+               alpha_config.src_color_mode=AA_SRC_NO_PRE_MUL;
+               alpha_config.src_factor_mode=AA_SRC_GLOBAL;
+               alpha_config.dst_factor_mode=AA_SRC_INVERSE;
+               break;
+       default:
+               pr_err("alpha mode error\n");
+               break;          
+       }
+       if((ppixel_alpha == 1)&&(global_alpha == 1)){
+               alpha_config.src_global_alpha_mode = AA_PER_PIX_GLOBAL;
+       }else if(ppixel_alpha == 1){
+               alpha_config.src_global_alpha_mode = AA_PER_PIX;
+       }else if(global_alpha == 1){
+               alpha_config.src_global_alpha_mode = AA_GLOBAL;
+       }else{
+               pr_err("alpha_en should be 0\n");
+       }
+       alpha_config.src_alpha_mode = AA_STRAIGHT;
+       alpha_config.src_alpha_cal_m0 = AA_NO_SAT;
+
+       switch(win_id){
+       case 0:
+               src_alpha_ctl = 0x60;
+               dst_alpha_ctl = 0x64;
+               break;
+       case 1:
+               src_alpha_ctl = 0xa0;
+               dst_alpha_ctl = 0xa4;
+               break;
+       case 2:
+               src_alpha_ctl = 0xdc;
+               dst_alpha_ctl = 0xec;
+               break;
+       case 3:
+               src_alpha_ctl = 0x12c;
+               dst_alpha_ctl = 0x13c;
+               break;
+       }
+       mask = m_WIN0_DST_FACTOR_M0;
+       val  = v_WIN0_DST_FACTOR_M0(alpha_config.dst_factor_mode);
+       lcdc_msk_reg(ctx, dst_alpha_ctl, mask, val);
+       mask = m_WIN0_SRC_ALPHA_EN | m_WIN0_SRC_COLOR_M0 |
+               m_WIN0_SRC_ALPHA_M0 | m_WIN0_SRC_BLEND_M0 |
+               m_WIN0_SRC_ALPHA_CAL_M0 | m_WIN0_SRC_FACTOR_M0|
+               m_WIN0_SRC_GLOBAL_ALPHA;
+       val = v_WIN0_SRC_ALPHA_EN(1) | 
+               v_WIN0_SRC_COLOR_M0(alpha_config.src_color_mode) |
+               v_WIN0_SRC_ALPHA_M0(alpha_config.src_alpha_mode) |
+               v_WIN0_SRC_BLEND_M0(alpha_config.src_global_alpha_mode) |
+               v_WIN0_SRC_ALPHA_CAL_M0(alpha_config.src_alpha_cal_m0) |
+               v_WIN0_SRC_FACTOR_M0(alpha_config.src_factor_mode) |
+               v_WIN0_SRC_GLOBAL_ALPHA(alpha_config.src_global_alpha_val);
+       lcdc_msk_reg(ctx, src_alpha_ctl, mask, val);
+
+       return 0;
+}
+static int rk3288_win_0_1_reg_update(struct fimd_context *ctx,int win_id)
+{
+       struct fimd_win_data *win_data;
+       unsigned int mask, val, off;
+       struct rk_screen *screen = ctx->screen;
+       u8 fmt_cfg = 0;
+       u32 xpos, ypos;
+       off = win_id * 0x40;
+       win_data = &ctx->win_data[win_id];
+       switch(win_data->bpp){
+               case 32:
+                       fmt_cfg = 0;
+                       break;
+               case 24:
+                       fmt_cfg = 1;
+                       break;
+               case 16:
+                       fmt_cfg = 2;
+                       break;
+               default:
+                       printk("not support format %d\n",win_data->bpp);
+                       break;
+       }
+
+       xpos = win_data->offset_x + screen->mode.left_margin + screen->mode.hsync_len;
+       ypos = win_data->offset_y + screen->mode.upper_margin + screen->mode.vsync_len;
+       mask =  m_WIN0_EN | m_WIN0_DATA_FMT ;
+       val  =  v_WIN0_EN(1) | v_WIN0_DATA_FMT(fmt_cfg);
+       lcdc_msk_reg(ctx, WIN0_CTRL0+off, mask,val);    
+
+       val =   v_WIN0_VIR_STRIDE(win_data->line_size/(win_data->bpp>>3));
+       lcdc_writel(ctx, WIN0_VIR+off, val);    
+       val =   v_WIN0_ACT_WIDTH(win_data->ovl_width) |
+               v_WIN0_ACT_HEIGHT(win_data->ovl_height);
+       lcdc_writel(ctx, WIN0_ACT_INFO+off, val); 
+
+       val =   v_WIN0_DSP_WIDTH(win_data->fb_width) |
+               v_WIN0_DSP_HEIGHT(win_data->fb_height);
+       lcdc_writel(ctx, WIN0_DSP_INFO+off, val); 
+
+       val =   v_WIN0_DSP_XST(xpos) |
+               v_WIN0_DSP_YST(ypos);
+       lcdc_writel(ctx, WIN0_DSP_ST+off, val); 
+       lcdc_writel(ctx, WIN0_YRGB_MST+off, win_data->dma_addr +win_data->buf_offsize );
+
+       if(win_id == 1)
+               rk3288_lcdc_alpha_cfg(ctx,win_id);
+       lcdc_cfg_done(ctx);
+       return 0;
+}
+
+static int rk3288_lcdc_post_cfg(struct fimd_context *ctx)
+{
+       struct rk_screen *screen = ctx->screen;
+       u16 x_res = screen->mode.xres;
+       u16 y_res = screen->mode.yres;
+       u32 mask, val;
+       u16 h_total,v_total;
+       u16 post_hsd_en,post_vsd_en;
+       u16 post_dsp_hact_st,post_dsp_hact_end; 
+       u16 post_dsp_vact_st,post_dsp_vact_end;
+       u16 post_dsp_vact_st_f1,post_dsp_vact_end_f1;
+       u16 post_h_fac,post_v_fac;
+
+       h_total = screen->mode.hsync_len+screen->mode.left_margin +
+                 x_res + screen->mode.right_margin;
+       v_total = screen->mode.vsync_len+screen->mode.upper_margin +
+                 y_res + screen->mode.lower_margin;
+
+       if(screen->post_dsp_stx + screen->post_xsize > x_res){          
+               printk(KERN_ERR"post:stx[%d] + xsize[%d] > x_res[%d]\n",
+                       screen->post_dsp_stx,screen->post_xsize,x_res);
+               screen->post_dsp_stx = x_res - screen->post_xsize;
+       }
+       if(screen->x_mirror == 0){
+               post_dsp_hact_st=screen->post_dsp_stx + 
+                       screen->mode.hsync_len+screen->mode.left_margin;
+               post_dsp_hact_end = post_dsp_hact_st + screen->post_xsize;
+       }else{
+               post_dsp_hact_end = h_total - screen->mode.right_margin -
+                                       screen->post_dsp_stx;
+               post_dsp_hact_st = post_dsp_hact_end - screen->post_xsize;
+       }       
+       if((screen->post_xsize < x_res)&&(screen->post_xsize != 0)){
+               post_hsd_en = 1;
+               post_h_fac = 
+                       GET_SCALE_FACTOR_BILI_DN(x_res , screen->post_xsize); 
+       }else{
+               post_hsd_en = 0;
+               post_h_fac = 0x1000;
+       }
+
+
+       if(screen->post_dsp_sty + screen->post_ysize > y_res){
+               printk(KERN_ERR "post:sty[%d] + ysize[%d] > y_res[%d]\n",
+                       screen->post_dsp_sty,screen->post_ysize,y_res);
+               screen->post_dsp_sty = y_res - screen->post_ysize;      
+       }
+       
+       if(screen->y_mirror == 0){
+               post_dsp_vact_st = screen->post_dsp_sty + 
+                       screen->mode.vsync_len+screen->mode.upper_margin;
+               post_dsp_vact_end = post_dsp_vact_st + screen->post_ysize;
+       }else{
+               post_dsp_vact_end = v_total - screen->mode.lower_margin -
+                                       - screen->post_dsp_sty;
+               post_dsp_hact_st = post_dsp_vact_end - screen->post_ysize;
+       }
+       if((screen->post_ysize < y_res)&&(screen->post_ysize != 0)){
+               post_vsd_en = 1;
+               post_v_fac = GET_SCALE_FACTOR_BILI_DN(y_res, screen->post_ysize);               
+       }else{
+               post_vsd_en = 0;
+               post_v_fac = 0x1000;
+       }
+
+       if(screen->interlace == 1){
+               post_dsp_vact_st_f1  = v_total + post_dsp_vact_st;
+               post_dsp_vact_end_f1 = post_dsp_vact_st_f1 + screen->post_ysize;
+       }else{
+               post_dsp_vact_st_f1  = 0;
+               post_dsp_vact_end_f1 = 0;
+       }
+       printk(KERN_ERR"post:xsize=%d,ysize=%d,xpos=%d,ypos=%d,"
+             "hsd_en=%d,h_fac=%d,vsd_en=%d,v_fac=%d\n",
+               screen->post_xsize,screen->post_ysize,screen->xpos,screen->ypos,
+               post_hsd_en,post_h_fac,post_vsd_en,post_v_fac);
+       mask = m_DSP_HACT_END_POST | m_DSP_HACT_ST_POST;
+       val = v_DSP_HACT_END_POST(post_dsp_hact_end) | 
+             v_DSP_HACT_ST_POST(post_dsp_hact_st);
+       lcdc_msk_reg(ctx, POST_DSP_HACT_INFO, mask, val);
+
+       mask = m_DSP_VACT_END_POST | m_DSP_VACT_ST_POST;
+       val = v_DSP_VACT_END_POST(post_dsp_vact_end) | 
+             v_DSP_VACT_ST_POST(post_dsp_vact_st);
+       lcdc_msk_reg(ctx, POST_DSP_VACT_INFO, mask, val);
+
+       mask = m_POST_HS_FACTOR_YRGB | m_POST_VS_FACTOR_YRGB;
+       val = v_POST_HS_FACTOR_YRGB(post_h_fac) |
+               v_POST_VS_FACTOR_YRGB(post_v_fac);
+       lcdc_msk_reg(ctx, POST_SCL_FACTOR_YRGB, mask, val);
+
+       mask = m_DSP_VACT_END_POST_F1 | m_DSP_VACT_ST_POST_F1;
+       val = v_DSP_VACT_END_POST_F1(post_dsp_vact_end_f1) |
+               v_DSP_VACT_ST_POST_F1(post_dsp_vact_st_f1);
+       lcdc_msk_reg(ctx, POST_DSP_VACT_INFO_F1, mask, val);
+
+       mask = m_POST_HOR_SD_EN | m_POST_VER_SD_EN;
+       val = v_POST_HOR_SD_EN(post_hsd_en) | v_POST_VER_SD_EN(post_vsd_en);
+       lcdc_msk_reg(ctx, POST_SCL_CTRL, mask, val);
+       return 0;
+}
+static void fimd_commit(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct rockchip_drm_panel_info *panel = ctx->panel;
+       struct rk_screen *screen = ctx->screen;
+       u16 hsync_len = screen->mode.hsync_len;
+       u16 left_margin = screen->mode.left_margin;
+       u16 right_margin = screen->mode.right_margin;
+       u16 vsync_len = screen->mode.vsync_len;
+       u16 upper_margin = screen->mode.upper_margin;
+       u16 lower_margin = screen->mode.lower_margin;
+       u16 x_res = screen->mode.xres;
+       u16 y_res = screen->mode.yres;
+       u32 mask, val;
+       int face;
+       u32 v=0;
+       u16 h_total,v_total;
+       h_total = hsync_len + left_margin  + x_res + right_margin;
+       v_total = vsync_len + upper_margin + y_res + lower_margin;
+       screen->post_dsp_stx=0;
+       screen->post_dsp_sty=0;
+       screen->post_xsize =x_res;
+       screen->post_ysize = y_res;
+
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if (ctx->suspended)
+               return;
+
+       printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if(!ctx->clkon)
+               return;
+#if 1
+       switch (screen->face) {
+               case OUT_P565:
+                       face = OUT_P565;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_P666:
+                       face = OUT_P666;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_D888_P565:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_D888_P666:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
+                               m_DITHER_DOWN_SEL;
+                       val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
+                               v_DITHER_DOWN_SEL(1);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_P888:
+                       face = OUT_P888;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       break;
+               default:
+                       printk("un supported interface!\n");
+                       break;
+       }
+       switch(screen->type){
+               case SCREEN_RGB:
+               case SCREEN_LVDS:
+               case SCREEN_DUAL_LVDS:                  
+                       mask = m_RGB_OUT_EN;
+                       val = v_RGB_OUT_EN(1);
+                       v = 1 << (3+16);
+                       v |= (ctx->lcdc_id << 3);
+                       break;
+               case SCREEN_HDMI:
+                       mask = m_HDMI_OUT_EN;
+                       val = v_HDMI_OUT_EN(1);
+                       /*v = 1 << (4+16);
+                         v |= (ctx->id << 4);*/        
+                       break;
+               case SCREEN_MIPI:
+                       mask = m_MIPI_OUT_EN;
+                       val = v_MIPI_OUT_EN(1);
+                       /*v = (1 << (6+16))||(1 << (9+16));
+                         v |= (ctx->id << 6);
+                         v |= (ctx->id << 9);*/                
+                       break;
+               case SCREEN_DUAL_MIPI:
+                       mask = m_MIPI_OUT_EN | m_DOUB_CHANNEL_EN;
+                       val = v_MIPI_OUT_EN(1) | v_DOUB_CHANNEL_EN(1);
+                       /*v = (1 << (6+16))||(1 << (9+16));
+                         v |= (ctx->id << 6);
+                         v |= (ctx->id << 9);*/        
+                       break;
+               case SCREEN_EDP:
+                       face = OUT_RGB_AAA;  /*RGB AAA output*/
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       lcdc_msk_reg(ctx, DSP_CTRL1, mask, val);
+                       mask = m_EDP_OUT_EN;
+                       val = v_EDP_OUT_EN(1);
+                       /*v = 1 << (5+16);
+                         v |= (ctx->id << 5);*/                
+                       break;
+       }
+       lcdc_msk_reg(ctx, SYS_CTRL, mask, val);
+#ifdef USE_ION_MMU
+       mask = m_MMU_EN;
+       val = v_MMU_EN(1);
+       lcdc_msk_reg(ctx, SYS_CTRL, mask, val);
+       mask = m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;
+       val = v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1);
+       lcdc_msk_reg(ctx, SYS_CTRL1, mask, val);                
+#endif 
+       writel_relaxed(v, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
+       mask = m_DSP_OUT_MODE | m_DSP_HSYNC_POL | m_DSP_VSYNC_POL |
+               m_DSP_DEN_POL | m_DSP_DCLK_POL | m_DSP_BG_SWAP | 
+               m_DSP_RB_SWAP | m_DSP_RG_SWAP | m_DSP_DELTA_SWAP |
+               m_DSP_DUMMY_SWAP | m_DSP_OUT_ZERO | m_DSP_BLANK_EN | 
+               m_DSP_BLACK_EN | m_DSP_X_MIR_EN | m_DSP_Y_MIR_EN;
+       val = v_DSP_OUT_MODE(face) | v_DSP_HSYNC_POL(screen->pin_hsync) |
+               v_DSP_VSYNC_POL(screen->pin_vsync) | 
+               v_DSP_DEN_POL(screen->pin_den) | v_DSP_DCLK_POL(screen->pin_dclk) |
+               v_DSP_BG_SWAP(screen->swap_gb) | v_DSP_RB_SWAP(screen->swap_rb) | 
+               v_DSP_RG_SWAP(screen->swap_rg) | 
+               v_DSP_DELTA_SWAP(screen->swap_delta) |
+               v_DSP_DUMMY_SWAP(screen->swap_dumy) | v_DSP_OUT_ZERO(0) | 
+               v_DSP_BLANK_EN(0) | v_DSP_BLACK_EN(0) |
+               v_DSP_X_MIR_EN(screen->x_mirror) | v_DSP_Y_MIR_EN(screen->y_mirror);
+       lcdc_msk_reg(ctx, DSP_CTRL0, mask, val);
+
+       mask = m_DSP_BG_BLUE | m_DSP_BG_GREEN | m_DSP_BG_RED;
+       val  = v_DSP_BG_BLUE(0x3ff) | v_DSP_BG_GREEN(0) | v_DSP_BG_RED(0);
+       lcdc_msk_reg(ctx, DSP_BG, mask, val);
+
+       mask = m_DSP_HS_PW | m_DSP_HTOTAL;
+       val = v_DSP_HS_PW(hsync_len) | v_DSP_HTOTAL(h_total);
+       lcdc_msk_reg(ctx, DSP_HTOTAL_HS_END, mask, val);
+
+       mask = m_DSP_HACT_END | m_DSP_HACT_ST;
+       val = v_DSP_HACT_END(hsync_len + left_margin + x_res) |
+               v_DSP_HACT_ST(hsync_len + left_margin);
+       lcdc_msk_reg(ctx, DSP_HACT_ST_END, mask, val);
+
+       mask = m_DSP_VS_PW | m_DSP_VTOTAL;
+       val = v_DSP_VS_PW(vsync_len) | v_DSP_VTOTAL(v_total);
+       lcdc_msk_reg(ctx, DSP_VTOTAL_VS_END, mask, val);
+
+       mask = m_DSP_VACT_END | m_DSP_VACT_ST;
+       val = v_DSP_VACT_END(vsync_len + upper_margin + y_res) |
+               v_DSP_VACT_ST(vsync_len + upper_margin);
+       lcdc_msk_reg(ctx, DSP_VACT_ST_END, mask, val);
+
+       rk3288_lcdc_post_cfg(ctx);
+#endif
+}
+
+static int fimd_enable_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       u32 val,mask;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ctx->suspended)
+               return -EPERM;
+
+       if (!test_and_set_bit(0, &ctx->irq_flags)) {
+               mask = m_FS_INTR_CLR | m_FS_INTR_EN | m_LINE_FLAG_INTR_CLR |
+                   m_LINE_FLAG_INTR_EN | m_BUS_ERROR_INTR_CLR | 
+                   m_BUS_ERROR_INTR_EN | m_DSP_LINE_FLAG_NUM;
+               val = v_FS_INTR_CLR(1) | v_FS_INTR_EN(1) | v_LINE_FLAG_INTR_CLR(0) |
+                   v_LINE_FLAG_INTR_EN(0) | v_BUS_ERROR_INTR_CLR(0) | v_BUS_ERROR_INTR_EN(0) ;
+               lcdc_msk_reg(ctx, INTR_CTRL0, mask, val);
+               lcdc_cfg_done(ctx);
+       }
+
+       return 0;
+}
+
+static void fimd_disable_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       u32 val,mask;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ctx->suspended)
+               return;
+
+       if (test_and_clear_bit(0, &ctx->irq_flags)) {
+               mask = m_DSP_HOLD_VALID_INTR_EN | m_FS_INTR_EN |
+                       m_LINE_FLAG_INTR_EN | m_BUS_ERROR_INTR_EN;
+               val = v_DSP_HOLD_VALID_INTR_EN(0) | v_FS_INTR_EN(0) |
+                       v_LINE_FLAG_INTR_EN(0) | v_BUS_ERROR_INTR_EN(0);
+               lcdc_msk_reg(ctx, INTR_CTRL0, mask, val);
+
+               mask = m_DSP_HOLD_VALID_INTR_CLR | m_FS_INTR_CLR |
+                       m_LINE_FLAG_INTR_CLR | m_LINE_FLAG_INTR_CLR;
+               val = v_DSP_HOLD_VALID_INTR_CLR(0) | v_FS_INTR_CLR(0) |
+                       v_LINE_FLAG_INTR_CLR(0) | v_BUS_ERROR_INTR_CLR(0);
+               lcdc_msk_reg(ctx, INTR_CTRL0, mask, val);
+
+               mask = m_WIN0_EMPTY_INTR_EN | m_WIN1_EMPTY_INTR_EN |
+                       m_WIN2_EMPTY_INTR_EN | m_WIN3_EMPTY_INTR_EN |
+                       m_HWC_EMPTY_INTR_EN | m_POST_BUF_EMPTY_INTR_EN |
+                       m_POST_BUF_EMPTY_INTR_EN;
+               val = v_WIN0_EMPTY_INTR_EN(0) | v_WIN1_EMPTY_INTR_EN(0) |
+                       v_WIN2_EMPTY_INTR_EN(0) | v_WIN3_EMPTY_INTR_EN(0) |
+                       v_HWC_EMPTY_INTR_EN(0) | v_POST_BUF_EMPTY_INTR_EN(0) |
+                       v_PWM_GEN_INTR_EN(0);
+               lcdc_msk_reg(ctx, INTR_CTRL1, mask, val);
+
+               mask = m_WIN0_EMPTY_INTR_CLR | m_WIN1_EMPTY_INTR_CLR |
+                       m_WIN2_EMPTY_INTR_CLR | m_WIN3_EMPTY_INTR_CLR |
+                       m_HWC_EMPTY_INTR_CLR | m_POST_BUF_EMPTY_INTR_CLR |
+                       m_POST_BUF_EMPTY_INTR_CLR;
+               val = v_WIN0_EMPTY_INTR_CLR(0) | v_WIN1_EMPTY_INTR_CLR(0) |
+                       v_WIN2_EMPTY_INTR_CLR(0) | v_WIN3_EMPTY_INTR_CLR(0) |
+                       v_HWC_EMPTY_INTR_CLR(0) | v_POST_BUF_EMPTY_INTR_CLR(0) |
+                       v_PWM_GEN_INTR_CLR(0);
+               lcdc_msk_reg(ctx, INTR_CTRL1, mask, val);               
+               lcdc_cfg_done(ctx);
+
+
+       }
+}
+
+static void fimd_wait_for_vblank(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       if (ctx->suspended)
+               return;
+
+       atomic_set(&ctx->wait_vsync_event, 1);
+
+       /*
+        * wait for FIMD to signal VSYNC interrupt or return after
+        * timeout which is set to 50ms (refresh rate of 20).
+        */
+       if (!wait_event_timeout(ctx->wait_vsync_queue,
+                               !atomic_read(&ctx->wait_vsync_event),
+                               DRM_HZ/20))
+               DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static struct rockchip_drm_manager_ops fimd_manager_ops = {
+       .dpms = fimd_dpms,
+       .apply = fimd_apply,
+       .commit = fimd_commit,
+       .enable_vblank = fimd_enable_vblank,
+       .disable_vblank = fimd_disable_vblank,
+       .wait_for_vblank = fimd_wait_for_vblank,
+};
+
+static void fimd_win_mode_set(struct device *dev,
+                             struct rockchip_drm_overlay *overlay)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int win;
+       unsigned long offset;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!overlay) {
+               dev_err(dev, "overlay is NULL\n");
+               return;
+       }
+
+       win = overlay->zpos;
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       offset = overlay->fb_x * (overlay->bpp >> 3);
+       offset += overlay->fb_y * overlay->pitch;
+
+       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+
+       win_data = &ctx->win_data[win];
+
+       win_data->offset_x = overlay->crtc_x;
+       win_data->offset_y = overlay->crtc_y;
+       win_data->ovl_width = overlay->crtc_width;
+       win_data->ovl_height = overlay->crtc_height;
+       win_data->fb_width = overlay->fb_width;
+       win_data->fb_height = overlay->fb_height;
+       win_data->dma_addr = overlay->dma_addr[0] + offset;
+       win_data->bpp = overlay->bpp;
+       win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
+                               (overlay->bpp >> 3);
+       win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+
+       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+                       win_data->offset_x, win_data->offset_y);
+       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+                       win_data->ovl_width, win_data->ovl_height);
+       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
+       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+                       overlay->fb_width, overlay->crtc_width);
+}
+
+static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data = &ctx->win_data[win];
+       u8 fmt_cfg = 0;
+
+#if 0
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+       switch(win_data->bpp){
+               case 32:
+                       fmt_cfg = 0;
+                       break;
+               case 24:
+                       fmt_cfg = 1;
+                       break;
+               case 16:
+                       fmt_cfg = 2;
+                       break;
+               default:
+                       printk("not support format %d\n",win_data->bpp);
+                       break;
+       }
+
+
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+       lcdc_msk_reg(ctx , SYS_CTRL, m_WIN0_FORMAT, v_WIN0_FORMAT(fmt_cfg));
+       printk(KERN_ERR"------>yzq %d  SYS_CTRL=%x \n",__LINE__,lcdc_readl(ctx,SYS_CTRL));
+#endif
+}
+
+static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+{
+//     struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+}
+
+static void fimd_win_commit(struct device *dev, int zpos)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       struct rk_screen *screen = ctx->screen;
+       int win = zpos;
+       unsigned long val,  size;
+       u32 xpos, ypos;
+
+//     printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+
+       if (ctx->suspended)
+               return;
+
+       if (!ctx->clkon)
+               return;
+//     printk(KERN_ERR"%s %d\n", __func__,__LINE__);
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       win_data = &ctx->win_data[win];
+       switch(win){
+               case 0:
+                       rk3288_win_0_1_reg_update(ctx,0);
+                       break;
+               case 1:
+//     printk(KERN_ERR"-->yzq dma_addr=%x buf_offsize=%x win_data->fb_width=%d \nwin_data->fb_height=%d win_data->ovl_height=%d  win_data->ovl_width=%d \n win_data->offset_x=%d win_data->offset_y=%d win_data->line_size=%d\n win_data->bpp=%d ",win_data->dma_addr,win_data->buf_offsize,win_data->fb_width,win_data->fb_height,win_data->ovl_height, win_data->ovl_width,win_data->offset_x,win_data->offset_y,win_data->line_size,win_data->bpp);
+                       rk3288_win_0_1_reg_update(ctx,1);
+                       break;
+               case 2:
+                       printk("----->yzq not support now win_id=%d\n",win);
+               //      rk3288_win_2_3_reg_update(ctx,2);
+                       break;
+               case 3:
+                       printk("----->yzq not support now win_id=%d\n",win);
+               //      rk3288_win_2_3_reg_update(ctx,3);
+                       break;
+               default:
+                       printk("----->yzq not support now win_id=%d\n",win);
+                       break;
+       }
+//     printk("----->yzq now win_id=%d\n",win);
+
+       //rk3288_lcdc_post_cfg(screen);
+       win_data->enabled = true;
+
+}
+
+static void fimd_win_disable(struct device *dev, int zpos)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int win = zpos;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (win == DEFAULT_ZPOS)
+               win = ctx->default_win;
+
+       if (win < 0 || win > WINDOWS_NR)
+               return;
+
+       win_data = &ctx->win_data[win];
+
+       if (ctx->suspended) {
+               /* do not resume this window*/
+               win_data->resume = false;
+               return;
+       }
+
+       win_data->enabled = false;
+}
+
+static struct rockchip_drm_overlay_ops fimd_overlay_ops = {
+       .mode_set = fimd_win_mode_set,
+       .commit = fimd_win_commit,
+       .disable = fimd_win_disable,
+};
+
+static struct rockchip_drm_manager fimd_manager = {
+       .pipe           = -1,
+       .ops            = &fimd_manager_ops,
+       .overlay_ops    = &fimd_overlay_ops,
+       .display_ops    = &fimd_display_ops,
+};
+
+static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
+{
+       struct fimd_context *ctx = (struct fimd_context *)dev_id;
+       struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
+       struct drm_device *drm_dev = subdrv->drm_dev;
+       struct rockchip_drm_manager *manager = subdrv->manager;
+       u32 intr0_reg;
+
+       intr0_reg = lcdc_readl(ctx, INTR_CTRL0);
+
+       if(intr0_reg & m_FS_INTR_STS){
+               lcdc_msk_reg(ctx, INTR_CTRL0, m_FS_INTR_CLR,
+                            v_FS_INTR_CLR(1));
+
+       }
+
+       /* check the crtc is detached already from encoder */
+       if (manager->pipe < 0)
+               goto out;
+
+       drm_handle_vblank(drm_dev, manager->pipe);
+       rockchip_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
+
+       /* set wait vsync event to zero and wake up queue. */
+       if (atomic_read(&ctx->wait_vsync_event)) {
+               atomic_set(&ctx->wait_vsync_event, 0);
+               DRM_WAKEUP(&ctx->wait_vsync_queue);
+       }
+out:
+       return IRQ_HANDLED;
+}
+
+static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = 1, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       drm_dev->irq_enabled = 1;
+
+       /*
+        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       drm_dev->vblank_disable_allowed = 1;
+
+       /* attach this sub driver to iommu mapping if supported. */
+       if (is_drm_iommu_supported(drm_dev))
+               drm_iommu_attach_device(drm_dev, dev);
+
+       return 0;
+}
+
+static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* detach this sub driver from iommu mapping if supported. */
+       if (is_drm_iommu_supported(drm_dev))
+               drm_iommu_detach_device(drm_dev, dev);
+}
+
+
+static void fimd_clear_win(struct fimd_context *ctx, int win)
+{
+       u32 val;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+}
+
+static int fimd_clock(struct fimd_context *ctx, bool enable)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+printk(KERN_ERR"---->yzq %s %d \n",__func__,__LINE__);
+       if (enable) {
+               if(ctx->clkon)
+                       return 0;
+               int ret;
+
+               ret = clk_prepare_enable(ctx->hclk);
+               if (ret < 0)
+                       return ret;
+
+               ret = clk_prepare_enable(ctx->dclk);
+               if (ret < 0)
+                       return ret;
+               
+               ret = clk_prepare_enable(ctx->aclk);
+               if (ret < 0)
+                       return ret;
+               ctx->clkon=1;
+       } else {
+               if(!ctx->clkon)
+                       return 0;
+               clk_disable_unprepare(ctx->aclk);
+               clk_disable_unprepare(ctx->dclk);
+               clk_disable_unprepare(ctx->hclk);
+               ctx->clkon=0;
+       }
+
+       return 0;
+}
+
+static void fimd_window_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int i;
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               win_data->resume = win_data->enabled;
+               fimd_win_disable(dev, i);
+       }
+       fimd_wait_for_vblank(dev);
+}
+
+static void fimd_window_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_win_data *win_data;
+       int i;
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               win_data->enabled = win_data->resume;
+               win_data->resume = false;
+       }
+}
+
+static int fimd_activate(struct fimd_context *ctx, bool enable)
+{
+       struct device *dev = ctx->subdrv.dev;
+       if (enable) {
+               int ret;
+
+               ret = fimd_clock(ctx, true);
+               if (ret < 0)
+                       return ret;
+
+               ctx->suspended = false;
+
+               /* if vblank was enabled status, enable it again. */
+               if (test_and_clear_bit(0, &ctx->irq_flags))
+                       fimd_enable_vblank(dev);
+
+               fimd_window_resume(dev);
+       } else {
+               fimd_window_suspend(dev);
+
+               fimd_clock(ctx, false);
+               ctx->suspended = true;
+       }
+
+       return 0;
+}
+
+int rk_fb_video_mode_from_timing(const struct display_timing *dt, 
+                               struct rk_screen *screen)
+{
+       screen->mode.pixclock = dt->pixelclock.typ;
+       screen->mode.left_margin = dt->hback_porch.typ;
+       screen->mode.right_margin = dt->hfront_porch.typ;
+       screen->mode.xres = dt->hactive.typ;
+       screen->mode.hsync_len = dt->hsync_len.typ;
+       screen->mode.upper_margin = dt->vback_porch.typ;
+       screen->mode.lower_margin = dt->vfront_porch.typ;
+       screen->mode.yres = dt->vactive.typ;
+       screen->mode.vsync_len = dt->vsync_len.typ;
+       screen->type = SCREEN_LVDS;
+       screen->lvds_format = LVDS_8BIT_2;
+       screen->face = OUT_D888_P666;
+
+       if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+               screen->pin_dclk = 1;
+       else
+               screen->pin_dclk = 0;
+       if(dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+               screen->pin_hsync = 1;
+       else
+               screen->pin_hsync = 0;
+       if(dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+               screen->pin_vsync = 1;
+       else
+               screen->pin_vsync = 0;
+       if(dt->flags & DISPLAY_FLAGS_DE_HIGH)
+               screen->pin_den = 1;
+       else
+               screen->pin_den = 0;
+       
+       return 0;
+       
+}
+
+int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
+{
+       struct display_timings *disp_timing;
+       struct display_timing *dt;
+       disp_timing = of_get_display_timings(np);
+       if (!disp_timing) {
+               pr_err("parse display timing err\n");
+               return -EINVAL;
+       }
+       dt = display_timings_get(disp_timing, 0);
+       rk_fb_video_mode_from_timing(dt, screen);
+       printk(KERN_ERR "dclk:%d\n"
+                        "hactive:%d\n"
+                        "hback_porch:%d\n"
+                        "hfront_porch:%d\n"
+                        "hsync_len:%d\n"
+                        "vactive:%d\n"
+                        "vback_porch:%d\n"
+                        "vfront_porch:%d\n"
+                        "vsync_len:%d\n"
+                        "screen_type:%d\n"
+                        "lvds_format:%d\n"
+                        "face:%d\n",
+                       dt->pixelclock.typ,
+                       dt->hactive.typ,
+                       dt->hback_porch.typ,
+                       dt->hfront_porch.typ,
+                       dt->hsync_len.typ,
+                       dt->vactive.typ,
+                       dt->vback_porch.typ,
+                       dt->vfront_porch.typ,
+                       dt->vsync_len.typ,
+                       dt->screen_type,
+                       dt->lvds_format,
+                       dt->face);
+       return 0;
+
+}
+
+static int fimd_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fimd_context *ctx;
+       struct rockchip_drm_subdrv *subdrv;
+       struct rockchip_drm_fimd_pdata *pdata;
+       struct rockchip_drm_panel_info *panel;
+       struct device_node *np = pdev->dev.of_node;
+       struct rk_screen *screen;
+       int prop;
+       int reg_len;
+       struct resource *res;
+       int win;
+       int val;
+       int ret = -EINVAL;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+       of_property_read_u32(np, "rockchip,prop", &prop);
+       if (prop == EXTEND) {
+               printk("---->%s not support lcdc EXTEND now\n",__func__);
+                       return 0;
+       }
+       if (of_property_read_u32(np, "rockchip,pwr18", &val))
+       {
+               printk("----->%s default set it as 3.xv power supply",__func__);
+       }
+       else{
+               if(val){
+                       printk("----->%s lcdc pwr is 1.8, not supply now",__func__);
+               }else{
+                       printk("----->%s lcdc pwr is 3.3v",__func__);
+               }
+       }
+
+       if (dev->of_node) {
+               panel = devm_kzalloc(dev, sizeof(struct rockchip_drm_panel_info), GFP_KERNEL);
+               screen = devm_kzalloc(dev, sizeof(struct rk_screen), GFP_KERNEL);
+               rk_fb_get_prmry_screen(screen);
+               memcpy(&panel->timing,&screen->mode,sizeof(struct fb_videomode)); 
+       } else {
+               DRM_ERROR("no platform data specified\n");
+               return -EINVAL;
+       }
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       ctx->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->regs))
+               return PTR_ERR(ctx->regs);
+       reg_len = resource_size(res);
+       ctx->regsbak = devm_kzalloc(dev,reg_len,GFP_KERNEL);
+       ctx->lcdc_id = rk3288_lcdc_get_id(res->start);  
+       ctx->screen = screen;
+       ctx->hclk = devm_clk_get(dev, "hclk_lcdc");
+       ctx->aclk = devm_clk_get(dev, "aclk_lcdc");
+       ctx->dclk = devm_clk_get(dev, "dclk_lcdc");
+
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0) {
+               dev_err(dev, "cannot find IRQ for lcdc%d\n",
+                       ctx->lcdc_id);
+               return -ENXIO;
+       }
+       ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
+                                                       0, "drm_fimd", ctx);
+       if (ret) {
+               dev_err(dev, "irq request failed.\n");
+               return ret;
+       }
+
+       ctx->default_win = 0;// pdata->default_win;
+       ctx->panel = panel;
+       DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
+       atomic_set(&ctx->wait_vsync_event, 0);
+
+       subdrv = &ctx->subdrv;
+
+       subdrv->dev = dev;
+       subdrv->manager = &fimd_manager;
+       subdrv->probe = fimd_subdrv_probe;
+       subdrv->remove = fimd_subdrv_remove;
+
+       mutex_init(&ctx->lock);
+
+       platform_set_drvdata(pdev, ctx);
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       
+       ret = clk_set_rate(ctx->dclk, ctx->screen->mode.pixclock);
+       if (ret)
+               printk( "set lcdc%d dclk failed\n", ctx->lcdc_id);
+       
+       fimd_activate(ctx, true);
+
+       if(trsm_lvds_ops != NULL){
+               printk(KERN_ERR"------>yzq enable lvds\n");     
+               trsm_lvds_ops->enable();
+       }
+       memcpy(ctx->regsbak,ctx->regs,reg_len);
+       rockchip_drm_subdrv_register(subdrv);
+
+       return 0;
+}
+
+static int fimd_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fimd_context *ctx = platform_get_drvdata(pdev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_drm_subdrv_unregister(&ctx->subdrv);
+
+       if (ctx->suspended)
+               goto out;
+
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_sync(dev);
+
+out:
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimd_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       /*
+        * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
+        * called here, an error would be returned by that interface
+        * because the usage_count of pm runtime is more than 1.
+        */
+       if (!pm_runtime_suspended(dev))
+               return fimd_activate(ctx, false);
+
+       return 0;
+}
+
+static int fimd_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       /*
+        * if entered to sleep when lcd panel was on, the usage_count
+        * of pm runtime would still be 1 so in this case, fimd driver
+        * should be on directly not drawing on pm runtime interface.
+        */
+       if (!pm_runtime_suspended(dev)) {
+               int ret;
+
+               ret = fimd_activate(ctx, true);
+               if (ret < 0)
+                       return ret;
+
+               /*
+                * in case of dpms on(standby), fimd_apply function will
+                * be called by encoder's dpms callback to update fimd's
+                * registers but in case of sleep wakeup, it's not.
+                * so fimd_apply function should be called at here.
+                */
+               fimd_apply(dev);
+       }
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int fimd_runtime_suspend(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return fimd_activate(ctx, false);
+}
+
+static int fimd_runtime_resume(struct device *dev)
+{
+       struct fimd_context *ctx = get_fimd_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return fimd_activate(ctx, true);
+}
+#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id rk3288_lcdc_dt_ids[] = {
+       {.compatible = "rockchip,rk3288-lcdc",},
+       {}
+};
+#endif
+
+static const struct dev_pm_ops fimd_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
+       SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
+};
+
+struct platform_driver fimd_driver = {
+       .probe          = fimd_probe,
+       .remove         = fimd_remove,
+       .id_table       = rk3288_lcdc_dt_ids,
+       .driver         = {
+               .name   = "rk3288-lcdc",
+               .owner  = THIS_MODULE,
+               .pm     = &fimd_pm_ops,
+               .of_match_table = of_match_ptr(rk3288_lcdc_dt_ids),
+       },
+};
diff --git a/drivers/gpu/drm/rockchip/rk3288_drm_fimd.h b/drivers/gpu/drm/rockchip/rk3288_drm_fimd.h
new file mode 100644 (file)
index 0000000..4999cd3
--- /dev/null
@@ -0,0 +1,1368 @@
+/********************************************************************
+**          display output interface supported by rockchip lcdc                       *
+********************************************************************/
+/* */
+#define OUT_P888            0  //24bit screen,connect to lcdc D0~D23
+#define OUT_P666            1  //18bit screen,connect to lcdc D0~D17
+#define OUT_P565            2
+#define OUT_S888x           4
+#define OUT_CCIR656         6
+#define OUT_S888            8
+#define OUT_S888DUMY        12
+#define OUT_RGB_AAA        15
+#define OUT_P16BPP4         24
+#define OUT_D888_P666       0x21       //18bit screen,connect to lcdc D2~D7, D10~D15, D18~D23
+#define OUT_D888_P565       0x22
+
+/*******************register definition**********************/
+
+#define REG_CFG_DONE                   (0x0000)
+#define VERSION_INFO                   (0x0004)
+#define m_RTL_VERSION                  (0xffff<<0)
+#define m_FPGA_VERSION                 (0xffff<<16)
+#define SYS_CTRL                       (0x0008)
+#define v_DIRECT_PATH_EN(x)            (((x)&1)<<0)
+#define v_DIRECT_PATCH_SEL(x)          (((x)&3)<<1)
+#define v_DOUB_CHANNEL_EN(x)           (((x)&1)<<3)
+#define v_DOUB_CH_OVERLAP_NUM(x)        (((x)&0xf)<<4)
+#define v_EDPI_HALT_EN(x)              (((x)&1)<<8)
+#define v_EDPI_WMS_MODE(x)              (((x)&1)<<9)
+#define v_EDPI_WMS_FS(x)                (((x)&1)<<10)
+#define v_RGB_OUT_EN(x)                 (((x)&1)<<12)
+#define v_HDMI_OUT_EN(x)                (((x)&1)<<13)
+#define v_EDP_OUT_EN(x)                 (((x)&1)<<14)
+#define v_MIPI_OUT_EN(x)                (((x)&1)<<15)
+#define v_DMA_BURST_LENGTH(x)          (((x)&3)<<18)
+#define v_MMU_EN(x)                            (((x)&1)<<20)
+#define v_DMA_STOP(x)                   (((x)&1)<<21)
+#define v_STANDBY_EN(x)                (((x)&1)<<22)
+#define v_AUTO_GATING_EN(x)            (((x)&1)<<23)
+
+#define m_DIRECT_PATH_EN               (1<<0)
+#define m_DIRECT_PATCH_SEL             (3<<1)
+#define m_DOUB_CHANNEL_EN              (1<<3)
+#define m_DOUB_CH_OVERLAP_NUM           (0xf<<4)
+#define m_EDPI_HALT_EN                 (1<<8)
+#define m_EDPI_WMS_MODE                 (1<<9)
+#define m_EDPI_WMS_FS                   (1<<10)
+#define m_RGB_OUT_EN                    (1<<12)
+#define m_HDMI_OUT_EN                   (1<<13)
+#define m_EDP_OUT_EN                    (1<<14)
+#define m_MIPI_OUT_EN                   (1<<15)
+#define m_DMA_BURST_LENGTH             (3<<18)
+#define m_MMU_EN                               (1<<20)
+#define m_DMA_STOP                     (1<<21)
+#define m_STANDBY_EN                   (1<<22)
+#define m_AUTO_GATING_EN               (1<<23)
+#define SYS_CTRL1                      (0x000c)
+#define v_NOC_HURRY_EN(x)               (((x)&0x1 )<<0 ) 
+#define v_NOC_HURRY_VALUE(x)            (((x)&0x3 )<<1 )
+#define v_NOC_HURRY_THRESHOLD(x)        (((x)&0x3f)<<3 )
+#define v_NOC_QOS_EN(x)                 (((x)&0x1 )<<9 )
+#define v_NOC_WIN_QOS(x)                (((x)&0x3 )<<10)
+#define v_AXI_MAX_OUTSTANDING_EN(x)     (((x)&0x1 )<<12)
+#define v_AXI_OUTSTANDING_MAX_NUM(x)    (((x)&0x1f)<<13)
+
+#define m_NOC_HURRY_EN                  (0x1 <<0 )
+#define m_NOC_HURRY_VALUE               (0x3 <<1 )
+#define m_NOC_HURRY_THRESHOLD           (0x3f<<3 )
+#define m_NOC_QOS_EN                    (0x1 <<9 )
+#define m_NOC_WIN_QOS                   (0x3 <<10)
+#define m_AXI_MAX_OUTSTANDING_EN        (0x1 <<12)
+#define m_AXI_OUTSTANDING_MAX_NUM       (0x1f<<13)
+
+#define DSP_CTRL0                      (0x0010)
+#define v_DSP_OUT_MODE(x)              (((x)&0x0f)<<0)
+#define v_DSP_HSYNC_POL(x)             (((x)&1)<<4)
+#define v_DSP_VSYNC_POL(x)             (((x)&1)<<5)
+#define v_DSP_DEN_POL(x)               (((x)&1)<<6)
+#define v_DSP_DCLK_POL(x)              (((x)&1)<<7)
+#define v_DSP_DCLK_DDR(x)              (((x)&1)<<8)
+#define v_DSP_DDR_PHASE(x)             (((x)&1)<<9)
+#define v_DSP_INTERLACE(x)             (((x)&1)<<10)
+#define v_DSP_FIELD_POL(x)             (((x)&1)<<11)
+#define v_DSP_BG_SWAP(x)               (((x)&1)<<12)
+#define v_DSP_RB_SWAP(x)               (((x)&1)<<13)
+#define v_DSP_RG_SWAP(x)               (((x)&1)<<14)
+#define v_DSP_DELTA_SWAP(x)            (((x)&1)<<15)
+#define v_DSP_DUMMY_SWAP(x)            (((x)&1)<<16)
+#define v_DSP_OUT_ZERO(x)              (((x)&1)<<17)
+#define v_DSP_BLANK_EN(x)              (((x)&1)<<18)
+#define v_DSP_BLACK_EN(x)              (((x)&1)<<19)
+#define v_DSP_CCIR656_AVG(x)           (((x)&1)<<20)
+#define v_DSP_YUV_CLIP(x)              (((x)&1)<<21)
+#define v_DSP_X_MIR_EN(x)              (((x)&1)<<22)
+#define v_DSP_Y_MIR_EN(x)              (((x)&1)<<23)
+#define m_DSP_OUT_MODE                 (0x0f<<0)
+#define m_DSP_HSYNC_POL                (1<<4)
+#define m_DSP_VSYNC_POL                (1<<5)
+#define m_DSP_DEN_POL                  (1<<6)
+#define m_DSP_DCLK_POL                 (1<<7)
+#define m_DSP_DCLK_DDR                 (1<<8)
+#define m_DSP_DDR_PHASE                (1<<9)
+#define m_DSP_INTERLACE                (1<<10)
+#define m_DSP_FIELD_POL                (1<<11)
+#define m_DSP_BG_SWAP                  (1<<12)
+#define m_DSP_RB_SWAP                  (1<<13)
+#define m_DSP_RG_SWAP                  (1<<14)
+#define m_DSP_DELTA_SWAP               (1<<15)
+#define m_DSP_DUMMY_SWAP                       (1<<16)
+#define m_DSP_OUT_ZERO                 (1<<17)
+#define m_DSP_BLANK_EN                 (1<<18)
+#define m_DSP_BLACK_EN                 (1<<19)
+#define m_DSP_CCIR656_AVG              (1<<20)
+#define m_DSP_YUV_CLIP                 (1<<21)
+#define m_DSP_X_MIR_EN                 (1<<22)
+#define m_DSP_Y_MIR_EN                 (1<<23)
+
+#define DSP_CTRL1                      (0x0014)
+#define v_DSP_LUT_EN(x)                (((x)&1)<<0)
+#define v_PRE_DITHER_DOWN_EN(x)        (((x)&1)<<1)
+#define v_DITHER_DOWN_EN(x)            (((x)&1)<<2)
+#define v_DITHER_DOWN_MODE(x)          (((x)&1)<<3)
+#define v_DITHER_DOWN_SEL(x)           (((x)&1)<<4)
+#define v_DITHER_UP_EN(x)              (((x)&1)<<6)
+#define v_DSP_LAYER0_SEL(x)            (((x)&3)<<8)
+#define v_DSP_LAYER1_SEL(x)            (((x)&3)<<10)
+#define v_DSP_LAYER2_SEL(x)            (((x)&3)<<12)
+#define v_DSP_LAYER3_SEL(x)            (((x)&3)<<14)
+#define m_DSP_LUT_EN                   (1<<0)
+#define m_PRE_DITHER_DOWN_EN           (1<<1)
+#define m_DITHER_DOWN_EN               (1<<2)
+#define m_DITHER_DOWN_MODE             (1<<3)
+#define m_DITHER_DOWN_SEL              (1<<4)
+#define m_DITHER_UP_EN                 (1<<6)
+#define m_DSP_LAYER0_SEL               (3<<8)
+#define m_DSP_LAYER1_SEL               (3<<10)
+#define m_DSP_LAYER2_SEL               (3<<12)
+#define m_DSP_LAYER3_SEL               (3<<16)
+
+#define DSP_BG                                 (0x0018)
+#define v_DSP_BG_BLUE(x)               (((x)&0x3ff)<<0)
+#define v_DSP_BG_GREEN(x)              (((x)&0x3ff)<<10)
+#define v_DSP_BG_RED(x)                (((x)&0x3ff)<<20)
+#define m_DSP_BG_BLUE                  (0x3ff<<0)
+#define m_DSP_BG_GREEN                 (0x3ff<<10)
+#define m_DSP_BG_RED                   (0x3ff<<20)
+
+#define MCU_CTRL                       (0x001c)
+#define v_MCU_PIX_TOTAL(x)             (((x)&0x3f)<<0)
+#define v_MCU_CS_PST(x)                (((x)&0xf)<<6)
+#define v_MCU_CS_PEND(x)               (((x)&0x3f)<<10)
+#define v_MCU_RW_PST(x)                (((x)&0xf)<<16)
+#define v_MCU_RW_PEND(x)               (((x)&0x3f)<<20)
+#define v_MCU_CLK_SEL(x)               (((x)&1)<<26)   
+#define v_MCU_HOLD_MODE(x)             (((x)&1)<<27)
+#define v_MCU_FRAME_ST(x)              (((x)&1)<<28)
+#define v_MCU_RS(x)                    (((x)&1)<<29)
+#define v_MCU_BYPASS(x)                (((x)&1)<<30)
+#define v_MCU_TYPE(x)                  (((x)&1)<<31)
+#define m_MCU_PIX_TOTAL                (0x3f<<0)
+#define m_MCU_CS_PST                   (0xf<<6)
+#define m_MCU_CS_PEND                  (0x3f<<10)
+#define m_MCU_RW_PST                   (0xf<<16)
+#define m_MCU_RW_PEND                  (0x3f<<20)
+#define m_MCU_CLK_SEL                  (1<<26)   
+#define m_MCU_HOLD_MODE                (1<<27)
+#define m_MCU_FRAME_ST                 (1<<28)
+#define m_MCU_RS                       (1<<29)
+#define m_MCU_BYPASS                   (1<<30)
+#define m_MCU_TYPE                     ((u32)1<<31)
+
+#define INTR_CTRL0                     (0x0020)
+#define v_DSP_HOLD_VALID_INTR_STS(x)    (((x)&1)<<0)
+#define v_FS_INTR_STS(x)               (((x)&1)<<1)
+#define v_LINE_FLAG_INTR_STS(x)        (((x)&1)<<2)
+#define v_BUS_ERROR_INTR_STS(x)        (((x)&1)<<3)
+#define v_DSP_HOLD_VALID_INTR_EN(x)    (((x)&1)<<4)
+#define v_FS_INTR_EN(x)                (((x)&1)<<5)
+#define v_LINE_FLAG_INTR_EN(x)         (((x)&1)<<6)
+#define v_BUS_ERROR_INTR_EN(x)         (((x)&1)<<7)
+#define v_DSP_HOLD_VALID_INTR_CLR(x)    (((x)&1)<<8)
+#define v_FS_INTR_CLR(x)               (((x)&1)<<9)
+#define v_LINE_FLAG_INTR_CLR(x)                (((x)&1)<<10)
+#define v_BUS_ERROR_INTR_CLR(x)                (((x)&1)<<11)
+#define v_DSP_LINE_FLAG_NUM(x)         (((x)&0xfff)<<12)
+
+#define m_DSP_HOLD_VALID_INTR_STS      (1<<0)
+#define m_FS_INTR_STS                  (1<<1)
+#define m_LINE_FLAG_INTR_STS           (1<<2)
+#define m_BUS_ERROR_INTR_STS           (1<<3)
+#define m_DSP_HOLD_VALID_INTR_EN       (1<<4)
+#define m_FS_INTR_EN                   (1<<5)
+#define m_LINE_FLAG_INTR_EN            (1<<6)
+#define m_BUS_ERROR_INTR_EN            (1<<7)
+#define m_DSP_HOLD_VALID_INTR_CLR      (1<<8)
+#define m_FS_INTR_CLR                  (1<<9)
+#define m_LINE_FLAG_INTR_CLR           (1<<10)
+#define m_BUS_ERROR_INTR_CLR           (1<<11)
+#define m_DSP_LINE_FLAG_NUM            (0xfff<<12)
+
+#define INTR_CTRL1                     (0x0024)
+#define v_WIN0_EMPTY_INTR_STS(x)       (((x)&1)<<0)
+#define v_WIN1_EMPTY_INTR_STS(x)       (((x)&1)<<1)
+#define v_WIN2_EMPTY_INTR_STS(x)       (((x)&1)<<2)
+#define v_WIN3_EMPTY_INTR_STS(x)       (((x)&1)<<3)
+#define v_HWC_EMPTY_INTR_STS(x)                (((x)&1)<<4)
+#define v_POST_BUF_EMPTY_INTR_STS(x)   (((x)&1)<<5)
+#define v_PWM_GEN_INTR_STS(x)          (((x)&1)<<6)
+#define v_WIN0_EMPTY_INTR_EN(x)                (((x)&1)<<8)
+#define v_WIN1_EMPTY_INTR_EN(x)                (((x)&1)<<9)
+#define v_WIN2_EMPTY_INTR_EN(x)                (((x)&1)<<10)
+#define v_WIN3_EMPTY_INTR_EN(x)                (((x)&1)<<11)
+#define v_HWC_EMPTY_INTR_EN(x)         (((x)&1)<<12)
+#define v_POST_BUF_EMPTY_INTR_EN(x)    (((x)&1)<<13)
+#define v_PWM_GEN_INTR_EN(x)           (((x)&1)<<14)
+#define v_WIN0_EMPTY_INTR_CLR(x)       (((x)&1)<<16)
+#define v_WIN1_EMPTY_INTR_CLR(x)       (((x)&1)<<17)
+#define v_WIN2_EMPTY_INTR_CLR(x)       (((x)&1)<<18)
+#define v_WIN3_EMPTY_INTR_CLR(x)       (((x)&1)<<19)
+#define v_HWC_EMPTY_INTR_CLR(x)                (((x)&1)<<20)
+#define v_POST_BUF_EMPTY_INTR_CLR(x)   (((x)&1)<<21)
+#define v_PWM_GEN_INTR_CLR(x)          (((x)&1)<<22)
+
+#define m_WIN0_EMPTY_INTR_STS          (1<<0)
+#define m_WIN1_EMPTY_INTR_STS          (1<<1)
+#define m_WIN2_EMPTY_INTR_STS          (1<<2)
+#define m_WIN3_EMPTY_INTR_STS          (1<<3)
+#define m_HWC_EMPTY_INTR_STS           (1<<4)
+#define m_POST_BUF_EMPTY_INTR_STS      (1<<5)
+#define m_PWM_GEN_INTR_STS             (1<<6)
+#define m_WIN0_EMPTY_INTR_EN           (1<<8)
+#define m_WIN1_EMPTY_INTR_EN           (1<<9)
+#define m_WIN2_EMPTY_INTR_EN           (1<<10)
+#define m_WIN3_EMPTY_INTR_EN           (1<<11)
+#define m_HWC_EMPTY_INTR_EN            (1<<12)
+#define m_POST_BUF_EMPTY_INTR_EN       (1<<13)
+#define m_PWM_GEN_INTR_EN              (1<<14)
+#define m_WIN0_EMPTY_INTR_CLR          (1<<16)
+#define m_WIN1_EMPTY_INTR_CLR          (1<<17)
+#define m_WIN2_EMPTY_INTR_CLR          (1<<18)
+#define m_WIN3_EMPTY_INTR_CLR          (1<<19)
+#define m_HWC_EMPTY_INTR_CLR           (1<<20)
+#define m_POST_BUF_EMPTY_INTR_CLR      (1<<21)
+#define m_PWM_GEN_INTR_CLR             (1<<22)
+
+/*win0 register*/
+#define WIN0_CTRL0                     (0x0030)
+#define v_WIN0_EN(x)                   (((x)&1)<<0)
+#define v_WIN0_DATA_FMT(x)             (((x)&7)<<1)
+#define v_WIN0_FMT_10(x)               (((x)&1)<<4)
+#define v_WIN0_LB_MODE(x)              (((x)&7)<<5)
+#define v_WIN0_INTERLACE_READ(x)       (((x)&1)<<8)
+#define v_WIN0_NO_OUTSTANDING(x)       (((x)&1)<<9)
+#define v_WIN0_CSC_MODE(x)             (((x)&3)<<10)
+#define v_WIN0_RB_SWAP(x)              (((x)&1)<<12)
+#define v_WIN0_ALPHA_SWAP(x)           (((x)&1)<<13)
+#define v_WIN0_MID_SWAP(x)             (((x)&1)<<14)
+#define v_WIN0_UV_SWAP(x)              (((x)&1)<<15)
+#define v_WIN0_PPAS_ZERO_EN(x)         (((x)&1)<<16)
+#define v_WIN0_YRGB_DEFLICK(x)         (((x)&1)<<18)
+#define v_WIN0_CBR_DEFLICK(x)          (((x)&1)<<19)
+#define v_WIN0_YUV_CLIP(x)             (((x)&1)<<20)
+
+#define m_WIN0_EN                      (1<<0)
+#define m_WIN0_DATA_FMT                (7<<1)
+#define m_WIN0_FMT_10                  (1<<4)
+#define m_WIN0_LB_MODE                         (3<<5)
+#define m_WIN0_INTERLACE_READ          (1<<8)
+#define m_WIN0_NO_OUTSTANDING          (1<<9)
+#define m_WIN0_CSC_MODE                (3<<10)
+#define m_WIN0_RB_SWAP                         (1<<12)
+#define m_WIN0_ALPHA_SWAP              (1<<13)
+#define m_WIN0_MID_SWAP                (1<<14)
+#define m_WIN0_UV_SWAP                         (1<<15)
+#define m_WIN0_PPAS_ZERO_EN            (1<<16)
+#define m_WIN0_YRGB_DEFLICK            (1<<18)
+#define m_WIN0_CBR_DEFLICK             (1<<19)
+#define m_WIN0_YUV_CLIP                (1<<20)
+
+#define WIN0_CTRL1                     (0x0034)
+#define v_WIN0_YRGB_AXI_GATHER_EN(x)   (((x)&1)<<0)
+#define v_WIN0_CBR_AXI_GATHER_EN(x)    (((x)&1)<<1)
+#define v_WIN0_BIC_COE_SEL(x)           (((x)&3)<<2)
+#define v_WIN0_VSD_YRGB_GT4(x)          (((x)&1)<<4)
+#define v_WIN0_VSD_YRGB_GT2(x)          (((x)&1)<<5)
+#define v_WIN0_VSD_CBR_GT4(x)           (((x)&1)<<6)
+#define v_WIN0_VSD_CBR_GT2(x)           (((x)&1)<<7)
+#define v_WIN0_YRGB_AXI_GATHER_NUM(x)  (((x)&0xf)<<8)
+#define v_WIN0_CBR_AXI_GATHER_NUM(x)   (((x)&7)<<12)
+#define v_WIN0_LINE_LOAD_MODE(x)       (((x)&1)<<15)
+#define v_WIN0_YRGB_HOR_SCL_MODE(x)    (((x)&3)<<16)
+#define v_WIN0_YRGB_VER_SCL_MODE(x)    (((x)&3)<<18)
+#define v_WIN0_YRGB_HSD_MODE(x)                (((x)&3)<<20)
+#define v_WIN0_YRGB_VSU_MODE(x)                (((x)&1)<<22)
+#define v_WIN0_YRGB_VSD_MODE(x)                (((x)&1)<<23)
+#define v_WIN0_CBR_HOR_SCL_MODE(x)     (((x)&3)<<24)
+#define v_WIN0_CBR_VER_SCL_MODE(x)     (((x)&3)<<26)
+#define v_WIN0_CBR_HSD_MODE(x)         (((x)&3)<<28)
+#define v_WIN0_CBR_VSU_MODE(x)         (((x)&1)<<30)
+#define v_WIN0_CBR_VSD_MODE(x)         (((x)&1)<<31)
+
+#define m_WIN0_YRGB_AXI_GATHER_EN      (1<<0)
+#define m_WIN0_CBR_AXI_GATHER_EN        (1<<1)
+#define m_WIN0_BIC_COE_SEL              (3<<2)
+#define m_WIN0_VSD_YRGB_GT4             (1<<4)
+#define m_WIN0_VSD_YRGB_GT2             (1<<5)
+#define m_WIN0_VSD_CBR_GT4              (1<<6)
+#define m_WIN0_VSD_CBR_GT2              (1<<7)
+#define m_WIN0_YRGB_AXI_GATHER_NUM     (0xf<<8)
+#define m_WIN0_CBR_AXI_GATHER_NUM      (7<<12)
+#define m_WIN0_LINE_LOAD_MODE          (1<<15)
+#define m_WIN0_YRGB_HOR_SCL_MODE       (3<<16)
+#define m_WIN0_YRGB_VER_SCL_MODE       (3<<18)
+#define m_WIN0_YRGB_HSD_MODE           (3<<20)
+#define m_WIN0_YRGB_VSU_MODE           (1<<22)
+#define m_WIN0_YRGB_VSD_MODE           (1<<23)
+#define m_WIN0_CBR_HOR_SCL_MODE                (3<<24)
+#define m_WIN0_CBR_VER_SCL_MODE                (3<<26)
+#define m_WIN0_CBR_HSD_MODE            (3<<28)
+#define m_WIN0_CBR_VSU_MODE            ((u32)1<<30)
+#define m_WIN0_CBR_VSD_MODE            ((u32)1<<31)
+
+#define WIN0_COLOR_KEY                 (0x0038)
+#define v_WIN0_COLOR_KEY(x)            (((x)&0x3fffffff)<<0)
+#define v_WIN0_COLOR_KEY_EN(x)         (((x)&1)<<31)
+#define m_WIN0_COLOR_KEY               (0x3fffffff<<0)
+#define m_WIN0_COLOR_KEY_EN            ((u32)1<<31)
+
+#define WIN0_VIR                       (0x003c)
+#define v_WIN0_VIR_STRIDE(x)           (((x)&0x3fff)<<0)
+#define v_WIN0_VIR_STRIDE_UV(x)                (((x)&0x3fff)<<16)
+#define m_WIN0_VIR_STRIDE              (0x3fff<<0)
+#define m_WIN0_VIR_STRIDE_UV           (0x3fff<<16)
+
+#define WIN0_YRGB_MST                  (0x0040)
+#define WIN0_CBR_MST                   (0x0044)
+#define WIN0_ACT_INFO                  (0x0048)
+#define v_WIN0_ACT_WIDTH(x)            (((x-1)&0x1fff)<<0)
+#define v_WIN0_ACT_HEIGHT(x)           (((x-1)&0x1fff)<<16)
+#define m_WIN0_ACT_WIDTH               (0x1fff<<0)
+#define m_WIN0_ACT_HEIGHT              (0x1fff<<16)
+
+#define WIN0_DSP_INFO                  (0x004c)
+#define v_WIN0_DSP_WIDTH(x)            (((x-1)&0xfff)<<0)
+#define v_WIN0_DSP_HEIGHT(x)           (((x-1)&0xfff)<<16)
+#define m_WIN0_DSP_WIDTH               (0xfff<<0)
+#define m_WIN0_DSP_HEIGHT              (0xfff<<16)
+
+#define WIN0_DSP_ST                    (0x0050)
+#define v_WIN0_DSP_XST(x)              (((x)&0x1fff)<<0)
+#define v_WIN0_DSP_YST(x)              (((x)&0x1fff)<<16)
+#define m_WIN0_DSP_XST                         (0x1fff<<0)
+#define m_WIN0_DSP_YST                         (0x1fff<<16)
+
+#define WIN0_SCL_FACTOR_YRGB           (0x0054)
+#define v_WIN0_HS_FACTOR_YRGB(x)       (((x)&0xffff)<<0)
+#define v_WIN0_VS_FACTOR_YRGB(x)       (((x)&0xffff)<<16)
+#define m_WIN0_HS_FACTOR_YRGB          (0xffff<<0)
+#define m_WIN0_VS_FACTOR_YRGB          ((u32)0xffff<<16)
+
+#define WIN0_SCL_FACTOR_CBR            (0x0058)
+#define v_WIN0_HS_FACTOR_CBR(x)                (((x)&0xffff)<<0)
+#define v_WIN0_VS_FACTOR_CBR(x)                (((x)&0xffff)<<16)
+#define m_WIN0_HS_FACTOR_CBR           (0xffff<<0)
+#define m_WIN0_VS_FACTOR_CBR           ((u32)0xffff<<16)
+
+#define WIN0_SCL_OFFSET                (0x005c)
+#define v_WIN0_HS_OFFSET_YRGB(x)       (((x)&0xff)<<0)
+#define v_WIN0_HS_OFFSET_CBR(x)                (((x)&0xff)<<8)
+#define v_WIN0_VS_OFFSET_YRGB(x)       (((x)&0xff)<<16)
+#define v_WIN0_VS_OFFSET_CBR(x)                (((x)&0xff)<<24)
+
+#define m_WIN0_HS_OFFSET_YRGB          (0xff<<0)
+#define m_WIN0_HS_OFFSET_CBR           (0xff<<8)
+#define m_WIN0_VS_OFFSET_YRGB          (0xff<<16)
+#define m_WIN0_VS_OFFSET_CBR           ((u32)0xff<<24)
+
+#define WIN0_SRC_ALPHA_CTRL            (0x0060)
+#define v_WIN0_SRC_ALPHA_EN(x)         (((x)&1)<<0)
+#define v_WIN0_SRC_COLOR_M0(x)         (((x)&1)<<1)
+#define v_WIN0_SRC_ALPHA_M0(x)         (((x)&1)<<2)
+#define v_WIN0_SRC_BLEND_M0(x)         (((x)&3)<<3)
+#define v_WIN0_SRC_ALPHA_CAL_M0(x)     (((x)&1)<<5)
+#define v_WIN0_SRC_FACTOR_M0(x)                (((x)&7)<<6)
+#define v_WIN0_SRC_GLOBAL_ALPHA(x)     (((x)&0xff)<<16)
+#define v_WIN0_FADING_VALUE(x)          (((x)&0xff)<<24)
+
+#define m_WIN0_SRC_ALPHA_EN            (1<<0)
+#define m_WIN0_SRC_COLOR_M0            (1<<1)
+#define m_WIN0_SRC_ALPHA_M0            (1<<2)
+#define m_WIN0_SRC_BLEND_M0            (3<<3)
+#define m_WIN0_SRC_ALPHA_CAL_M0                (1<<5)
+#define m_WIN0_SRC_FACTOR_M0           (7<<6)
+#define m_WIN0_SRC_GLOBAL_ALPHA                (0xff<<16)
+#define m_WIN0_FADING_VALUE            (0xff<<24)
+
+#define WIN0_DST_ALPHA_CTRL            (0x0064)
+#define v_WIN0_DST_FACTOR_M0(x)                (((x)&7)<<6)
+#define m_WIN0_DST_FACTOR_M0           (7<<6)
+#define WIN0_FADING_CTRL               (0x0068)
+#define v_WIN0_FADING_OFFSET_R(x)      (((x)&0xff)<<0)
+#define v_WIN0_FADING_OFFSET_G(x)      (((x)&0xff)<<8)
+#define v_WIN0_FADING_OFFSET_B(x)      (((x)&0xff)<<16)
+#define v_WIN0_FADING_EN(x)            (((x)&1)<<24)
+
+#define m_WIN0_FADING_OFFSET_R                 (0xff<<0)
+#define m_WIN0_FADING_OFFSET_G                 (0xff<<8)
+#define m_WIN0_FADING_OFFSET_B                 (0xff<<16)
+#define m_WIN0_FADING_EN               (1<<24)
+
+/*win1 register*/
+#define WIN1_CTRL0                     (0x0070)
+#define v_WIN1_EN(x)                   (((x)&1)<<0)
+#define v_WIN1_DATA_FMT(x)             (((x)&7)<<1)
+#define v_WIN1_FMT_10(x)               (((x)&1)<<4)
+#define v_WIN1_LB_MODE(x)              (((x)&7)<<5)
+#define v_WIN1_INTERLACE_READ_MODE(x)  (((x)&1)<<8)
+#define v_WIN1_NO_OUTSTANDING(x)       (((x)&1)<<9)
+#define v_WIN1_CSC_MODE(x)             (((x)&3)<<10)
+#define v_WIN1_RB_SWAP(x)              (((x)&1)<<12)
+#define v_WIN1_ALPHA_SWAP(x)           (((x)&1)<<13)
+#define v_WIN1_MID_SWAP(x)             (((x)&1)<<14)
+#define v_WIN1_UV_SWAP(x)              (((x)&1)<<15)
+#define v_WIN1_PPAS_ZERO_EN(x)         (((x)&1)<<16)
+#define v_WIN1_YRGB_DEFLICK(x)         (((x)&1)<<18)
+#define v_WIN1_CBR_DEFLICK(x)          (((x)&1)<<19)
+#define v_WIN1_YUV_CLIP(x)             (((x)&1)<<20)
+
+#define m_WIN1_EN                      (1<<0)
+#define m_WIN1_DATA_FMT                        (7<<1)
+#define m_WIN1_FMT_10                  (1<<4)
+#define m_WIN1_LB_MODE                 (3<<5)
+#define m_WIN1_INTERLACE_READ_MODE     (1<<8)
+#define m_WIN1_NO_OUTSTANDING          (1<<9)
+#define m_WIN1_CSC_MODE                (3<<10)
+#define m_WIN1_RB_SWAP                         (1<<12)
+#define m_WIN1_ALPHA_SWAP              (1<<13)
+#define m_WIN1_MID_SWAP                (1<<14)
+#define m_WIN1_UV_SWAP                         (1<<15)
+#define m_WIN1_PPAS_ZERO_EN             (1<<16)
+#define m_WIN1_YRGB_DEFLICK            (1<<18)
+#define m_WIN1_CBR_DEFLICK             (1<<19)
+#define m_WIN1_YUV_CLIP                (1<<20)
+
+#define WIN1_CTRL1                     (0x0074)
+#define v_WIN1_YRGB_AXI_GATHER_EN(x)   (((x)&1)<<0)
+#define v_WIN1_CBR_AXI_GATHER_EN(x)    (((x)&1)<<1)
+#define v_WIN1_BIC_COE_SEL(x)           (((x)&3)<<2)
+#define v_WIN1_VSD_YRGB_GT4(x)          (((x)&1)<<4)
+#define v_WIN1_VSD_YRGB_GT2(x)          (((x)&1)<<5)
+#define v_WIN1_VSD_CBR_GT4(x)           (((x)&1)<<6)
+#define v_WIN1_VSD_CBR_GT2(x)           (((x)&1)<<7)
+#define v_WIN1_YRGB_AXI_GATHER_NUM(x)  (((x)&0xf)<<8)
+#define v_WIN1_CBR_AXI_GATHER_NUM(x)   (((x)&7)<<12)
+#define v_WIN1_LINE_LOAD_MODE(x)       (((x)&1)<<15)
+#define v_WIN1_YRGB_HOR_SCL_MODE(x)    (((x)&3)<<16)
+#define v_WIN1_YRGB_VER_SCL_MODE(x)    (((x)&3)<<18)
+#define v_WIN1_YRGB_HSD_MODE(x)                (((x)&3)<<20)
+#define v_WIN1_YRGB_VSU_MODE(x)                (((x)&1)<<22)
+#define v_WIN1_YRGB_VSD_MODE(x)                (((x)&1)<<23)
+#define v_WIN1_CBR_HOR_SCL_MODE(x)     (((x)&3)<<24)
+#define v_WIN1_CBR_VER_SCL_MODE(x)     (((x)&3)<<26)
+#define v_WIN1_CBR_HSD_MODE(x)         (((x)&3)<<28)
+#define v_WIN1_CBR_VSU_MODE(x)         (((x)&1)<<30)
+#define v_WIN1_CBR_VSD_MODE(x)         (((x)&1)<<31)
+
+#define m_WIN1_YRGB_AXI_GATHER_EN      (1<<0)
+#define m_WIN1_CBR_AXI_GATHER_EN       (1<<1)
+#define m_WIN1_BIC_COE_SEL              (3<<2)
+#define m_WIN1_VSD_YRGB_GT4             (1<<4)
+#define m_WIN1_VSD_YRGB_GT2             (1<<5)
+#define m_WIN1_VSD_CBR_GT4              (1<<6)
+#define m_WIN1_VSD_CBR_GT2              (1<<7)
+#define m_WIN1_YRGB_AXI_GATHER_NUM     (0xf<<8)
+#define m_WIN1_CBR_AXI_GATHER_NUM      (7<<12)
+#define m_WIN1_LINE_LOAD_MODE          (1<<15)
+#define m_WIN1_YRGB_HOR_SCL_MODE       (3<<16)
+#define m_WIN1_YRGB_VER_SCL_MODE       (3<<18)
+#define m_WIN1_YRGB_HSD_MODE           (3<<20)
+#define m_WIN1_YRGB_VSU_MODE           (1<<22)
+#define m_WIN1_YRGB_VSD_MODE           (1<<23)
+#define m_WIN1_CBR_HOR_SCL_MODE                (3<<24)
+#define m_WIN1_CBR_VER_SCL_MODE                (3<<26)
+#define m_WIN1_CBR_HSD_MODE            (3<<28)
+#define m_WIN1_CBR_VSU_MODE            (1<<30)
+#define m_WIN1_CBR_VSD_MODE            ((u32)1<<31)
+
+#define WIN1_COLOR_KEY                         (0x0078)
+#define v_WIN1_COLOR_KEY(x)            (((x)&0x3fffffff)<<0)
+#define v_WIN1_COLOR_KEY_EN(x)         (((x)&1)<<31)
+#define m_WIN1_COLOR_KEY               (0x3fffffff<<0)
+#define m_WIN1_COLOR_KEY_EN            ((u32)1<<31)
+
+#define WIN1_VIR                       (0x007c)
+#define v_WIN1_VIR_STRIDE(x)           (((x)&0x3fff)<<0)
+#define v_WIN1_VIR_STRIDE_UV(x)                (((x)&0x3fff)<<16)
+#define m_WIN1_VIR_STRIDE              (0x3fff<<0)
+#define m_WIN1_VIR_STRIDE_UV           (0x3fff<<16)
+
+#define WIN1_YRGB_MST                  (0x0080)
+#define WIN1_CBR_MST                   (0x0084)
+#define WIN1_ACT_INFO                  (0x0088)
+#define v_WIN1_ACT_WIDTH(x)            (((x-1)&0x1fff)<<0)
+#define v_WIN1_ACT_HEIGHT(x)           (((x-1)&0x1fff)<<16)
+#define m_WIN1_ACT_WIDTH               (0x1fff<<0)
+#define m_WIN1_ACT_HEIGHT              (0x1fff<<16)
+
+#define WIN1_DSP_INFO                  (0x008c)
+#define v_WIN1_DSP_WIDTH(x)            (((x-1)&0xfff)<<0)
+#define v_WIN1_DSP_HEIGHT(x)           (((x-1)&0xfff)<<16)
+#define m_WIN1_DSP_WIDTH               (0xfff<<0)
+#define m_WIN1_DSP_HEIGHT              (0xfff<<16)
+
+#define WIN1_DSP_ST                    (0x0090)
+#define v_WIN1_DSP_XST(x)              (((x)&0x1fff)<<0)
+#define v_WIN1_DSP_YST(x)              (((x)&0x1fff)<<16)
+#define m_WIN1_DSP_XST                         (0x1fff<<0)
+#define m_WIN1_DSP_YST                         (0x1fff<<16)
+
+#define WIN1_SCL_FACTOR_YRGB           (0x0094)
+#define v_WIN1_HS_FACTOR_YRGB(x)       (((x)&0xffff)<<0)
+#define v_WIN1_VS_FACTOR_YRGB(x)       (((x)&0xffff)<<16)
+#define m_WIN1_HS_FACTOR_YRGB          (0xffff<<0)
+#define m_WIN1_VS_FACTOR_YRGB          ((u32)0xffff<<16)
+
+#define WIN1_SCL_FACTOR_CBR            (0x0098)
+#define v_WIN1_HS_FACTOR_CBR(x)                (((x)&0xffff)<<0)
+#define v_WIN1_VS_FACTOR_CBR(x)                (((x)&0xffff)<<16)
+#define m_WIN1_HS_FACTOR_CBR           (0xffff<<0)
+#define m_WIN1_VS_FACTOR_CBR           ((u32)0xffff<<16)
+
+#define WIN1_SCL_OFFSET                (0x009c)
+#define v_WIN1_HS_OFFSET_YRGB(x)       (((x)&0xff)<<0)
+#define v_WIN1_HS_OFFSET_CBR(x)                (((x)&0xff)<<8)
+#define v_WIN1_VS_OFFSET_YRGB(x)       (((x)&0xff)<<16)
+#define v_WIN1_VS_OFFSET_CBR(x)                (((x)&0xff)<<24)
+
+#define m_WIN1_HS_OFFSET_YRGB          (0xff<<0)
+#define m_WIN1_HS_OFFSET_CBR           (0xff<<8)
+#define m_WIN1_VS_OFFSET_YRGB          (0xff<<16)
+#define m_WIN1_VS_OFFSET_CBR           ((u32)0xff<<24)
+
+#define WIN1_SRC_ALPHA_CTRL            (0x00a0)
+#define v_WIN1_SRC_ALPHA_EN(x)         (((x)&1)<<0)
+#define v_WIN1_SRC_COLOR_M0(x)         (((x)&1)<<1)
+#define v_WIN1_SRC_ALPHA_M0(x)         (((x)&1)<<2)
+#define v_WIN1_SRC_BLEND_M0(x)         (((x)&3)<<3)
+#define v_WIN1_SRC_ALPHA_CAL_M0(x)     (((x)&1)<<5)
+#define v_WIN1_SRC_FACTOR_M0(x)                (((x)&7)<<6)
+#define v_WIN1_SRC_GLOBAL_ALPHA(x)     (((x)&0xff)<<16)
+#define v_WIN1_FADING_VALUE(x)          (((x)&0xff)<<24)
+
+#define m_WIN1_SRC_ALPHA_EN            (1<<0)
+#define m_WIN1_SRC_COLOR_M0            (1<<1)
+#define m_WIN1_SRC_ALPHA_M0            (1<<2)
+#define m_WIN1_SRC_BLEND_M0            (3<<3)
+#define m_WIN1_SRC_ALPHA_CAL_M0                (1<<5)
+#define m_WIN1_SRC_FACTOR_M0           (7<<6)
+#define m_WIN1_SRC_GLOBAL_ALPHA                (0xff<<16)
+#define m_WIN1_FADING_VALUE            (0xff<<24)
+
+#define WIN1_DST_ALPHA_CTRL            (0x00a4)
+#define v_WIN1_DST_FACTOR_M0(x)                (((x)&7)<<6)
+#define m_WIN1_DST_FACTOR_M0           (7<<6)
+
+#define WIN1_FADING_CTRL               (0x00a8)
+#define v_WIN1_FADING_OFFSET_R(x)      (((x)&0xff)<<0)
+#define v_WIN1_FADING_OFFSET_G(x)      (((x)&0xff)<<8)
+#define v_WIN1_FADING_OFFSET_B(x)      (((x)&0xff)<<16)
+#define v_WIN1_FADING_EN(x)            (((x)&1)<<24)
+
+#define m_WIN1_FADING_OFFSET_R                 (0xff<<0)
+#define m_WIN1_FADING_OFFSET_G                 (0xff<<8)
+#define m_WIN1_FADING_OFFSET_B                 (0xff<<16)
+#define m_WIN1_FADING_EN               (1<<24)
+
+/*win2 register*/
+#define WIN2_CTRL0                     (0x00b0)
+#define v_WIN2_EN(x)                   (((x)&1)<<0)
+#define v_WIN2_DATA_FMT(x)             (((x)&7)<<1)
+#define v_WIN2_MST0_EN(x)              (((x)&1)<<4)
+#define v_WIN2_MST1_EN(x)              (((x)&1)<<5)
+#define v_WIN2_MST2_EN(x)              (((x)&1)<<6)
+#define v_WIN2_MST3_EN(x)              (((x)&1)<<7)
+#define v_WIN2_INTERLACE_READ(x)       (((x)&1)<<8)
+#define v_WIN2_NO_OUTSTANDING(x)       (((x)&1)<<9)
+#define v_WIN2_CSC_MODE(x)             (((x)&1)<<10)
+#define v_WIN2_RB_SWAP(x)              (((x)&1)<<12)
+#define v_WIN2_ALPHA_SWAP(x)           (((x)&1)<<13)
+#define v_WIN2_ENDIAN_MODE(x)          (((x)&1)<<14)
+#define v_WIN2_LUT_EN(x)               (((x)&1)<<18)
+
+#define m_WIN2_EN                      (1<<0)
+#define m_WIN2_DATA_FMT                (7<<1)
+#define m_WIN2_MST0_EN                         (1<<4)
+#define m_WIN2_MST1_EN                         (1<<5)
+#define m_WIN2_MST2_EN                         (1<<6)
+#define m_WIN2_MST3_EN                         (1<<7)
+#define m_WIN2_INTERLACE_READ          (1<<8)
+#define m_WIN2_NO_OUTSTANDING          (1<<9)
+#define m_WIN2_CSC_MODE                (1<<10)
+#define m_WIN2_RB_SWAP                         (1<<12)
+#define m_WIN2_ALPHA_SWAP              (1<<13)
+#define m_WIN2_ENDIAN_MODE             (1<<14)
+#define m_WIN2_LUT_EN                  (1<<18)
+
+#define WIN2_CTRL1                     (0x00b4)
+#define v_WIN2_AXI_GATHER_EN(x)                (((x)&1)<<0)
+#define v_WIN2_AXI_GATHER_NUM(x)       (((x)&0xf)<<4)
+#define m_WIN2_AXI_GATHER_EN           (1<<0)
+#define m_WIN2_AXI_GATHER_NUM          (0xf<<4)
+
+#define WIN2_VIR0_1                    (0x00b8)
+#define v_WIN2_VIR_STRIDE0(x)          (((x)&0x1fff)<<0)
+#define v_WIN2_VIR_STRIDE1(x)          (((x)&0x1fff)<<16)
+#define m_WIN2_VIR_STRIDE0             (0x1fff<<0)
+#define m_WIN2_VIR_STRIDE1             (0x1fff<<16)
+
+#define WIN2_VIR2_3                    (0x00bc)
+#define v_WIN2_VIR_STRIDE2(x)          (((x)&0x1fff)<<0)
+#define v_WIN2_VIR_STRIDE3(x)          (((x)&0x1fff)<<16)
+#define m_WIN2_VIR_STRIDE2             (0x1fff<<0)
+#define m_WIN2_VIR_STRIDE3             (0x1fff<<16)
+
+#define WIN2_MST0                      (0x00c0)
+#define WIN2_DSP_INFO0                         (0x00c4)
+#define v_WIN2_DSP_WIDTH0(x)           (((x-1)&0xfff)<<0)
+#define v_WIN2_DSP_HEIGHT0(x)          (((x-1)&0xfff)<<16)
+#define m_WIN2_DSP_WIDTH0              (0xfff<<0)
+#define m_WIN2_DSP_HEIGHT0             (0xfff<<16)
+
+#define WIN2_DSP_ST0                   (0x00c8)
+#define v_WIN2_DSP_XST0(x)             (((x)&0x1fff)<<0)
+#define v_WIN2_DSP_YST0(x)             (((x)&0x1fff)<<16)
+#define m_WIN2_DSP_XST0                        (0x1fff<<0)
+#define m_WIN2_DSP_YST0                        (0x1fff<<16)
+
+#define WIN2_COLOR_KEY                         (0x00cc)
+#define v_WIN2_COLOR_KEY(x)            (((x)&0xffffff)<<0)
+#define v_WIN2_KEY_EN(x)               (((x)&1)<<24)
+#define m_WIN2_COLOR_KEY               (0xffffff<<0)
+#define m_WIN2_KEY_EN                  ((u32)1<<24)
+
+
+#define WIN2_MST1                      (0x00d0) 
+#define WIN2_DSP_INFO1                         (0x00d4)
+#define v_WIN2_DSP_WIDTH1(x)           (((x-1)&0xfff)<<0)
+#define v_WIN2_DSP_HEIGHT1(x)          (((x-1)&0xfff)<<16)
+
+#define m_WIN2_DSP_WIDTH1              (0xfff<<0)
+#define m_WIN2_DSP_HEIGHT1             (0xfff<<16)
+
+#define WIN2_DSP_ST1                   (0x00d8)
+#define v_WIN2_DSP_XST1(x)             (((x)&0x1fff)<<0)
+#define v_WIN2_DSP_YST1(x)             (((x)&0x1fff)<<16)
+
+#define m_WIN2_DSP_XST1                        (0x1fff<<0)
+#define m_WIN2_DSP_YST1                        (0x1fff<<16)
+
+#define WIN2_SRC_ALPHA_CTRL            (0x00dc)
+#define v_WIN2_SRC_ALPHA_EN(x)         (((x)&1)<<0)
+#define v_WIN2_SRC_COLOR_M0(x)         (((x)&1)<<1)
+#define v_WIN2_SRC_ALPHA_M0(x)         (((x)&1)<<2)
+#define v_WIN2_SRC_BLEND_M0(x)         (((x)&3)<<3)
+#define v_WIN2_SRC_ALPHA_CAL_M0(x)     (((x)&1)<<5)
+#define v_WIN2_SRC_FACTOR_M0(x)                (((x)&7)<<5)
+#define v_WIN2_SRC_GLOBAL_ALPHA(x)     (((x)&0xff)<<16)
+#define v_WIN2_FADING_VALUE(x)          (((x)&0xff)<<24)
+
+
+#define m_WIN2_SRC_ALPHA_EN            (1<<0)
+#define m_WIN2_SRC_COLOR_M0            (1<<1)
+#define m_WIN2_SRC_ALPHA_M0            (1<<2)
+#define m_WIN2_SRC_BLEND_M0            (3<<3)
+#define m_WIN2_SRC_ALPHA_CAL_M0                (1<<5)
+#define m_WIN2_SRC_FACTOR_M0           (7<<6)
+#define m_WIN2_SRC_GLOBAL_ALPHA                (0xff<<16)
+#define m_WIN2_FADING_VALUE            (0xff<<24)
+
+#define WIN2_MST2                      (0x00e0)
+#define WIN2_DSP_INFO2                         (0x00e4)
+#define v_WIN2_DSP_WIDTH2(x)           (((x-1)&0xfff)<<0)
+#define v_WIN2_DSP_HEIGHT2(x)          (((x-1)&0xfff)<<16)
+
+#define m_WIN2_DSP_WIDTH2              (0xfff<<0)
+#define m_WIN2_DSP_HEIGHT2             (0xfff<<16)
+
+
+#define WIN2_DSP_ST2                   (0x00e8)
+#define v_WIN2_DSP_XST2(x)             (((x)&0x1fff)<<0)
+#define v_WIN2_DSP_YST2(x)             (((x)&0x1fff)<<16)
+#define m_WIN2_DSP_XST2                (0x1fff<<0)
+#define m_WIN2_DSP_YST2                (0x1fff<<16)
+
+#define WIN2_DST_ALPHA_CTRL            (0x00ec)
+#define v_WIN2_DST_FACTOR_M0(x)                (((x)&7)<<6)
+#define m_WIN2_DST_FACTOR_M0           (7<<6)
+
+#define WIN2_MST3                      (0x00f0)
+#define WIN2_DSP_INFO3                         (0x00f4)
+#define v_WIN2_DSP_WIDTH3(x)           (((x-1)&0xfff)<<0)
+#define v_WIN2_DSP_HEIGHT3(x)          (((x-1)&0xfff)<<16)
+#define m_WIN2_DSP_WIDTH3              (0xfff<<0)
+#define m_WIN2_DSP_HEIGHT3             (0xfff<<16)
+
+#define WIN2_DSP_ST3                   (0x00f8)
+#define v_WIN2_DSP_XST3(x)             (((x)&0x1fff)<<0)
+#define v_WIN2_DSP_YST3(x)             (((x)&0x1fff)<<16)
+#define m_WIN2_DSP_XST3                (0x1fff<<0)
+#define m_WIN2_DSP_YST3                (0x1fff<<16)
+
+#define WIN2_FADING_CTRL               (0x00fc)
+#define v_WIN2_FADING_OFFSET_R(x)      (((x)&0xff)<<0)
+#define v_WIN2_FADING_OFFSET_G(x)      (((x)&0xff)<<8)
+#define v_WIN2_FADING_OFFSET_B(x)      (((x)&0xff)<<16)
+#define v_WIN2_FADING_EN(x)            (((x)&1)<<24)
+
+#define m_WIN2_FADING_OFFSET_R                 (0xff<<0)
+#define m_WIN2_FADING_OFFSET_G                 (0xff<<8)
+#define m_WIN2_FADING_OFFSET_B                 (0xff<<16)
+#define m_WIN2_FADING_EN               (1<<24)
+
+/*win3 register*/
+#define WIN3_CTRL0                     (0x0100)
+#define v_WIN3_EN(x)                   (((x)&1)<<0)
+#define v_WIN3_DATA_FMT(x)             (((x)&7)<<1)
+#define v_WIN3_MST0_EN(x)              (((x)&1)<<4)
+#define v_WIN3_MST1_EN(x)              (((x)&1)<<5)
+#define v_WIN3_MST2_EN(x)              (((x)&1)<<6)
+#define v_WIN3_MST3_EN(x)              (((x)&1)<<7)
+#define v_WIN3_INTERLACE_READ(x)       (((x)&1)<<8)
+#define v_WIN3_NO_OUTSTANDING(x)       (((x)&1)<<9)
+#define v_WIN3_CSC_MODE(x)             (((x)&1)<<10)
+#define v_WIN3_RB_SWAP(x)              (((x)&1)<<12)
+#define v_WIN3_ALPHA_SWAP(x)           (((x)&1)<<13)
+#define v_WIN3_ENDIAN_MODE(x)          (((x)&1)<<14)
+#define v_WIN3_LUT_EN(x)               (((x)&1)<<18)
+
+#define m_WIN3_EN                      (1<<0)
+#define m_WIN3_DATA_FMT                (7<<1)
+#define m_WIN3_MST0_EN                         (1<<4)
+#define m_WIN3_MST1_EN                         (1<<5)
+#define m_WIN3_MST2_EN                         (1<<6)
+#define m_WIN3_MST3_EN                         (1<<7)
+#define m_WIN3_INTERLACE_READ          (1<<8)
+#define m_WIN3_NO_OUTSTANDING          (1<<9)
+#define m_WIN3_CSC_MODE                (1<<10)
+#define m_WIN3_RB_SWAP                         (1<<12)
+#define m_WIN3_ALPHA_SWAP              (1<<13)
+#define m_WIN3_ENDIAN_MODE             (1<<14)
+#define m_WIN3_LUT_EN                  (1<<18)
+
+
+#define WIN3_CTRL1                     (0x0104)
+#define v_WIN3_AXI_GATHER_EN(x)                (((x)&1)<<0)
+#define v_WIN3_AXI_GATHER_NUM(x)       (((x)&0xf)<<4)
+#define m_WIN3_AXI_GATHER_EN           (1<<0)
+#define m_WIN3_AXI_GATHER_NUM          (0xf<<4)
+
+#define WIN3_VIR0_1                    (0x0108)
+#define v_WIN3_VIR_STRIDE0(x)          (((x)&0x1fff)<<0)
+#define v_WIN3_VIR_STRIDE1(x)          (((x)&0x1fff)<<16)
+#define m_WIN3_VIR_STRIDE0             (0x1fff<<0)
+#define m_WIN3_VIR_STRIDE1             (0x1fff<<16)
+
+#define WIN3_VIR2_3                    (0x010c)
+#define v_WIN3_VIR_STRIDE2(x)          (((x)&0x1fff)<<0)
+#define v_WIN3_VIR_STRIDE3(x)          (((x)&0x1fff)<<16)
+#define m_WIN3_VIR_STRIDE2             (0x1fff<<0)
+#define m_WIN3_VIR_STRIDE3             (0x1fff<<16)
+
+#define WIN3_MST0                      (0x0110)
+#define WIN3_DSP_INFO0                         (0x0114)
+#define v_WIN3_DSP_WIDTH0(x)           (((x-1)&0xfff)<<0)
+#define v_WIN3_DSP_HEIGHT0(x)          (((x-1)&0xfff)<<16)
+#define m_WIN3_DSP_WIDTH0              (0xfff<<0)
+#define m_WIN3_DSP_HEIGHT0             (0xfff<<16)
+
+#define WIN3_DSP_ST0                   (0x0118)
+#define v_WIN3_DSP_XST0(x)             (((x)&0x1fff)<<0)
+#define v_WIN3_DSP_YST0(x)             (((x)&0x1fff)<<16)
+#define m_WIN3_DSP_XST0                        (0x1fff<<0)
+#define m_WIN3_DSP_YST0                        (0x1fff<<16)
+
+#define WIN3_COLOR_KEY                         (0x011c)
+#define v_WIN3_COLOR_KEY(x)            (((x)&0xffffff)<<0)
+#define v_WIN3_KEY_EN(x)               (((x)&1)<<24)
+#define m_WIN3_COLOR_KEY               (0xffffff<<0)
+#define m_WIN3_KEY_EN                  ((u32)1<<24)
+
+#define WIN3_MST1                      (0x0120)
+#define WIN3_DSP_INFO1                         (0x0124)
+#define v_WIN3_DSP_WIDTH1(x)           (((x-1)&0xfff)<<0)
+#define v_WIN3_DSP_HEIGHT1(x)          (((x-1)&0xfff)<<16)
+#define m_WIN3_DSP_WIDTH1              (0xfff<<0)
+#define m_WIN3_DSP_HEIGHT1             (0xfff<<16)
+
+#define WIN3_DSP_ST1                   (0x0128)
+#define v_WIN3_DSP_XST1(x)             (((x)&0x1fff)<<0)
+#define v_WIN3_DSP_YST1(x)             (((x)&0x1fff)<<16)
+#define m_WIN3_DSP_XST1                        (0x1fff<<0)
+#define m_WIN3_DSP_YST1                        (0x1fff<<16)
+
+#define WIN3_SRC_ALPHA_CTRL            (0x012c)
+#define v_WIN3_SRC_ALPHA_EN(x)         (((x)&1)<<0)
+#define v_WIN3_SRC_COLOR_M0(x)         (((x)&1)<<1)
+#define v_WIN3_SRC_ALPHA_M0(x)         (((x)&1)<<2)
+#define v_WIN3_SRC_BLEND_M0(x)         (((x)&3)<<3)
+#define v_WIN3_SRC_ALPHA_CAL_M0(x)     (((x)&1)<<5)
+#define v_WIN3_SRC_FACTOR_M0(x)                (((x)&7)<<6)
+#define v_WIN3_SRC_GLOBAL_ALPHA(x)     (((x)&0xff)<<16)
+#define v_WIN3_FADING_VALUE(x)          (((x)&0xff)<<24)
+
+#define m_WIN3_SRC_ALPHA_EN            (1<<0)
+#define m_WIN3_SRC_COLOR_M0            (1<<1)
+#define m_WIN3_SRC_ALPHA_M0            (1<<2)
+#define m_WIN3_SRC_BLEND_M0            (3<<3)
+#define m_WIN3_SRC_ALPHA_CAL_M0                (1<<5)
+#define m_WIN3_SRC_FACTOR_M0           (7<<6)
+#define m_WIN3_SRC_GLOBAL_ALPHA                (0xff<<16)
+#define m_WIN3_FADING_VALUE            (0xff<<24)
+
+#define WIN3_MST2                      (0x0130)
+#define WIN3_DSP_INFO2                         (0x0134)
+#define v_WIN3_DSP_WIDTH2(x)           (((x-1)&0xfff)<<0)
+#define v_WIN3_DSP_HEIGHT2(x)          (((x-1)&0xfff)<<16)
+#define m_WIN3_DSP_WIDTH2              (0xfff<<0)
+#define m_WIN3_DSP_HEIGHT2             (0xfff<<16)
+
+#define WIN3_DSP_ST2                   (0x0138)
+#define v_WIN3_DSP_XST2(x)             (((x)&0x1fff)<<0)
+#define v_WIN3_DSP_YST2(x)             (((x)&0x1fff)<<16)
+#define m_WIN3_DSP_XST2                        (0x1fff<<0)
+#define m_WIN3_DSP_YST2                        (0x1fff<<16)
+
+#define WIN3_DST_ALPHA_CTRL            (0x013c)
+#define v_WIN3_DST_FACTOR_M0(x)                (((x)&7)<<6)
+#define m_WIN3_DST_FACTOR_M0           (7<<6)
+
+
+#define WIN3_MST3                      (0x0140)
+#define WIN3_DSP_INFO3                         (0x0144)
+#define v_WIN3_DSP_WIDTH3(x)           (((x-1)&0xfff)<<0)
+#define v_WIN3_DSP_HEIGHT3(x)          (((x-1)&0xfff)<<16)
+#define m_WIN3_DSP_WIDTH3              (0xfff<<0)
+#define m_WIN3_DSP_HEIGHT3             (0xfff<<16)
+
+#define WIN3_DSP_ST3                   (0x0148)
+#define v_WIN3_DSP_XST3(x)             (((x)&0x1fff)<<0)
+#define v_WIN3_DSP_YST3(x)             (((x)&0x1fff)<<16)
+#define m_WIN3_DSP_XST3                        (0x1fff<<0)
+#define m_WIN3_DSP_YST3                        (0x1fff<<16)
+
+#define WIN3_FADING_CTRL               (0x014c)
+#define v_WIN3_FADING_OFFSET_R(x)      (((x)&0xff)<<0)
+#define v_WIN3_FADING_OFFSET_G(x)      (((x)&0xff)<<8)
+#define v_WIN3_FADING_OFFSET_B(x)      (((x)&0xff)<<16)
+#define v_WIN3_FADING_EN(x)            (((x)&1)<<24)
+
+#define m_WIN3_FADING_OFFSET_R                 (0xff<<0)
+#define m_WIN3_FADING_OFFSET_G                 (0xff<<8)
+#define m_WIN3_FADING_OFFSET_B                 (0xff<<16)
+#define m_WIN3_FADING_EN               (1<<24)
+
+
+/*hwc register*/
+#define HWC_CTRL0                      (0x0150)
+#define v_HWC_EN(x)                    (((x)&1)<<0)
+#define v_HWC_DATA_FMT(x)              (((x)&7)<<1)
+#define v_HWC_MODE(x)                  (((x)&1)<<4)
+#define v_HWC_SIZE(x)                  (((x)&3)<<5)
+#define v_HWC_INTERLACE_READ(x)                (((x)&1)<<8)
+#define v_HWC_NO_OUTSTANDING(x)                (((x)&1)<<9)
+#define v_HWC_CSC_MODE(x)              (((x)&1)<<10)
+#define v_HWC_RB_SWAP(x)               (((x)&1)<<12)
+#define v_HWC_ALPHA_SWAP(x)            (((x)&1)<<13)
+#define v_HWC_ENDIAN_MODE(x)           (((x)&1)<<14)
+#define v_HWC_LUT_EN(x)                        (((x)&1)<<18)
+
+#define m_HWC_EN                       (1<<0)
+#define m_HWC_DATA_FMT                 (7<<1)
+#define m_HWC_MODE                     (1<<4)
+#define m_HWC_SIZE                     (3<<5)
+#define m_HWC_INTERLACE_READ           (1<<8)
+#define m_HWC_NO_OUTSTANDING           (1<<9)
+#define m_HWC_CSC_MODE                 (1<<10)
+#define m_HWC_RB_SWAP                  (1<<12)
+#define m_HWC_ALPHA_SWAP               (1<<13)
+#define m_HWC_ENDIAN_MODE              (1<<14)
+#define m_HWC_LUT_EN                   (1<<18)
+
+
+#define HWC_CTRL1                      (0x0154)
+#define v_HWC_AXI_GATHER_EN(x)         (((x)&1)<<0)
+#define v_HWC_AXI_GATHER_NUM(x)                (((x)&7)<<4)
+#define m_HWC_AXI_GATHER_EN            (1<<0)
+#define m_HWC_AXI_GATHER_NUM           (7<<4)
+
+#define HWC_MST                        (0x0158)
+#define HWC_DSP_ST                     (0x015c)
+#define v_HWC_DSP_XST3(x)              (((x)&0x1fff)<<0)
+#define v_HWC_DSP_YST3(x)              (((x)&0x1fff)<<16)
+#define m_HWC_DSP_XST3                 (0x1fff<<0)
+#define m_HWC_DSP_YST3                 (0x1fff<<16)
+
+#define HWC_SRC_ALPHA_CTRL             (0x0160)
+#define v_HWC_SRC_ALPHA_EN(x)          (((x)&1)<<0)
+#define v_HWC_SRC_COLOR_M0(x)          (((x)&1)<<1)
+#define v_HWC_SRC_ALPHA_M0(x)          (((x)&1)<<2)
+#define v_HWC_SRC_BLEND_M0(x)          (((x)&3)<<3)
+#define v_HWC_SRC_ALPHA_CAL_M0(x)      (((x)&1)<<5)
+#define v_HWC_SRC_FACTOR_M0(x)         (((x)&7)<<6)
+#define v_HWC_SRC_GLOBAL_ALPHA(x)      (((x)&0xff)<<16)
+#define v_HWC_FADING_VALUE(x)           (((x)&0xff)<<24)
+
+#define m_HWC_SRC_ALPHA_EN             (1<<0)
+#define m_HWC_SRC_COLOR_M0             (1<<1)
+#define m_HWC_SRC_ALPHA_M0             (1<<2)
+#define m_HWC_SRC_BLEND_M0             (3<<3)
+#define m_HWC_SRC_ALPHA_CAL_M0         (1<<5)
+#define m_HWC_SRC_FACTOR_M0            (7<<6)
+#define m_HWC_SRC_GLOBAL_ALPHA         (0xff<<16)
+#define m_HWC_FADING_VALUE             (0xff<<24)
+
+#define HWC_DST_ALPHA_CTRL             (0x0164)
+#define v_HWC_DST_FACTOR_M0(x)         (((x)&7)<<6)
+#define m_HWC_DST_FACTOR_M0            (7<<6)
+
+
+#define HWC_FADING_CTRL                (0x0168)
+#define v_HWC_FADING_OFFSET_R(x)        (((x)&0xff)<<0)
+#define v_HWC_FADING_OFFSET_G(x)        (((x)&0xff)<<8)
+#define v_HWC_FADING_OFFSET_B(x)        (((x)&0xff)<<16)
+#define v_HWC_FADING_EN(x)             (((x)&1)<<24)
+
+#define m_HWC_FADING_OFFSET_R          (0xff<<0)
+#define m_HWC_FADING_OFFSET_G          (0xff<<8)
+#define m_HWC_FADING_OFFSET_B          (0xff<<16)
+#define m_HWC_FADING_EN                 (1<<24)
+
+/*post process register*/
+#define POST_DSP_HACT_INFO             (0x0170)
+#define v_DSP_HACT_END_POST(x)         (((x)&0x1fff)<<0)
+#define v_DSP_HACT_ST_POST(x)          (((x)&0x1fff)<<16)
+#define m_DSP_HACT_END_POST            (0x1fff<<0)
+#define m_DSP_HACT_ST_POST             (0x1fff<<16)
+
+#define POST_DSP_VACT_INFO             (0x0174)
+#define v_DSP_VACT_END_POST(x)         (((x)&0x1fff)<<0)
+#define v_DSP_VACT_ST_POST(x)          (((x)&0x1fff)<<16)
+#define m_DSP_VACT_END_POST            (0x1fff<<0)
+#define m_DSP_VACT_ST_POST             (0x1fff<<16)
+
+#define POST_SCL_FACTOR_YRGB           (0x0178)
+#define v_POST_HS_FACTOR_YRGB(x)       (((x)&0xffff)<<0)
+#define v_POST_VS_FACTOR_YRGB(x)       (((x)&0xffff)<<16)
+#define m_POST_HS_FACTOR_YRGB          (0xffff<<0)
+#define m_POST_VS_FACTOR_YRGB          (0xffff<<16)
+
+#define POST_SCL_CTRL                  (0x0180)
+#define v_POST_HOR_SD_EN(x)            (((x)&1)<<0)
+#define v_POST_VER_SD_EN(x)            (((x)&1)<<1)
+
+#define m_POST_HOR_SD_EN               (0x1<<0)
+#define m_POST_VER_SD_EN               (0x1<<1)
+
+#define POST_DSP_VACT_INFO_F1          (0x0184)
+#define v_DSP_VACT_END_POST_F1(x)       (((x)&0x1fff)<<0)
+#define v_DSP_VACT_ST_POST_F1(x)        (((x)&0x1fff)<<16)
+
+#define m_DSP_VACT_END_POST_F1          (0x1fff<<0)
+#define m_DSP_VACT_ST_POST_F1           (0x1fff<<16)
+
+#define DSP_HTOTAL_HS_END              (0x0188)
+#define v_DSP_HS_PW(x)                 (((x)&0x1fff)<<0)
+#define v_DSP_HTOTAL(x)                        (((x)&0x1fff)<<16)
+#define m_DSP_HS_PW                    (0x1fff<<0)
+#define m_DSP_HTOTAL                   (0x1fff<<16)
+
+#define DSP_HACT_ST_END                (0x018c)
+#define v_DSP_HACT_END(x)              (((x)&0x1fff)<<0)
+#define v_DSP_HACT_ST(x)               (((x)&0x1fff)<<16)
+#define m_DSP_HACT_END                 (0x1fff<<0)
+#define m_DSP_HACT_ST                  (0x1fff<<16)
+
+#define DSP_VTOTAL_VS_END              (0x0190)
+#define v_DSP_VS_PW(x)                 (((x)&0x1fff)<<0)
+#define v_DSP_VTOTAL(x)                        (((x)&0x1fff)<<16)
+#define m_DSP_VS_PW                    (0x1fff<<0)
+#define m_DSP_VTOTAL                   (0x1fff<<16)
+
+#define DSP_VACT_ST_END                (0x0194)
+#define v_DSP_VACT_END(x)              (((x)&0x1fff)<<0)
+#define v_DSP_VACT_ST(x)               (((x)&0x1fff)<<16)
+#define m_DSP_VACT_END                 (0x1fff<<0)
+#define m_DSP_VACT_ST                  (0x1fff<<16)
+
+#define DSP_VS_ST_END_F1               (0x0198)
+#define v_DSP_VS_END_F1(x)             (((x)&0x1fff)<<0)
+#define v_DSP_VS_ST_F1(x)              (((x)&0x1fff)<<16)
+#define m_DSP_VS_END_F1                        (0x1fff<<0)
+#define m_DSP_VS_ST_F1                 (0x1fff<<16)
+
+#define DSP_VACT_ST_END_F1             (0x019c)
+#define v_DSP_VACT_END_F1(x)           (((x)&0x1fff)<<0)
+#define v_DSP_VAC_ST_F1(x)             (((x)&0x1fff)<<16)
+#define m_DSP_VACT_END_F1              (0x1fff<<0)
+#define m_DSP_VAC_ST_F1                        (0x1fff<<16)
+
+
+/*pwm register*/
+#define PWM_CTRL                       (0x01a0)
+#define v_PWM_EN(x)                    (((x)&1)<<0)
+#define v_PWM_MODE(x)                  (((x)&3)<<1)
+
+#define v_DUTY_POL(x)                  (((x)&1)<<3)
+#define v_INACTIVE_POL(x)              (((x)&1)<<4)
+#define v_OUTPUT_MODE(x)               (((x)&1)<<5)
+#define v_BL_EN(x)                     (((x)&1)<<8)
+#define v_CLK_SEL(x)                   (((x)&1)<<9)
+#define v_PRESCALE(x)                  (((x)&7)<<12)
+#define v_SCALE(x)                     (((x)&0xff)<<16)
+#define v_RPT(x)                       (((x)&0xff)<<24)
+
+#define m_PWM_EN                       (1<<0)
+#define m_PWM_MODE                     (3<<1)
+
+#define m_DUTY_POL                     (1<<3)
+#define m_INACTIVE_POL                 (1<<4)
+#define m_OUTPUT_MODE                  (1<<5)
+#define m_BL_EN                                (1<<8)
+#define m_CLK_SEL                      (1<<9)
+#define m_PRESCALE                     (7<<12)
+#define m_SCALE                                (0xff<<16)
+#define m_RPT                          ((u32)0xff<<24)
+
+#define PWM_PERIOD_HPR                         (0x01a4)
+#define PWM_DUTY_LPR                   (0x01a8)
+#define PWM_CNT                        (0x01ac)
+
+/*BCSH register*/
+#define BCSH_COLOR_BAR                         (0x01b0)
+#define v_BCSH_EN(x)                   (((x)&1)<<0)
+#define v_BCSH_COLOR_BAR_Y(x)          (((x)&0x3ff)<<2)
+#define v_BCSH_COLOR_BAR_U(x)          (((x)&0x3ff)<<12)
+#define v_BCSH_COLOR_BAR_V(x)          (((x)&0x3ff)<<22)
+
+#define m_BCSH_EN                      (1<<0)
+#define m_BCSH_COLOR_BAR_Y             (0x3ff<<2)
+#define m_BCSH_COLOR_BAR_U             (0x3ff<<12)
+#define m_BCSH_COLOR_BAR_V             ((u32)0x3ff<<22)
+
+#define BCSH_BCS                       (0x01b4)
+#define v_BCSH_BRIGHTNESS(x)           (((x)&0xff)<<0) 
+#define v_BCSH_CONTRAST(x)             (((x)&0x1ff)<<8)        
+#define v_BCSH_SAT_CON(x)              (((x)&0x3ff)<<20)       
+#define v_BCSH_OUT_MODE(x)             (((x)&0x3)<<30) 
+
+#define m_BCSH_BRIGHTNESS              (0xff<<0)       
+#define m_BCSH_CONTRAST                        (0x1ff<<8)
+#define m_BCSH_SAT_CON                 (0x3ff<<20)     
+#define m_BCSH_OUT_MODE                        ((u32)0x3<<30)  
+
+
+#define BCSH_H                                 (0x01b8) 
+#define v_BCSH_SIN_HUE(x)              (((x)&0x1ff)<<0)
+#define v_BCSH_COS_HUE(x)              (((x)&0x1ff)<<16)
+
+#define m_BCSH_SIN_HUE                 (0x1ff<<0)
+#define m_BCSH_COS_HUE                 (0x1ff<<16)
+
+#define CABC_CTRL0                     (0x01c0)
+#define v_CABC_EN(x)                   (((x)&1)<<0)
+#define v_CABC_CALC_PIXEL_NUM(x)       (((x)&0x7fffff)<<1)
+#define v_CABC_STAGE_UP(x)             (((x)&0xff)<<24)
+#define m_CABC_EN                      (1<<0)
+#define m_CABC_CALC_PIXEL_NUM          (0x7fffff<<1)
+#define m_CABC_STAGE_UP                        (0xff<<24)
+
+
+#define CABC_CTRL1                     (0x01c4)
+#define v_CABC_TOTAL_NUM(x)            (((x)&0x7fffff)<<1)
+#define v_CABC_STAGE_DOWN(x)           (((x)&0xff)<<24)
+#define m_CABC_TOTAL_NUM               (0x7fffff<<1)
+#define m_CABC_STAGE_DOWN              (0xff<<24)
+
+#define CABC_GAUSS_LINE0_0             (0x01c8)
+#define v_CABC_T_LINE0_0(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE0_1(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE0_2(x)            (((x)&0xff)<<16)
+#define v_CABC_T_LINE0_3(x)            (((x)&0xff)<<24)
+#define m_CABC_T_LINE0_0               (0xff<<0)
+#define m_CABC_T_LINE0_1               (0xff<<8)
+#define m_CABC_T_LINE0_2               (0xff<<16)
+#define m_CABC_T_LINE0_3               ((u32)0xff<<24)
+
+#define CABC_GAUSS_LINE0_1             (0x01cc)
+#define v_CABC_T_LINE0_4(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE0_5(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE0_6(x)            (((x)&0xff)<<16)
+#define m_CABC_T_LINE0_4               (0xff<<0)
+#define m_CABC_T_LINE0_5               (0xff<<8)
+#define m_CABC_T_LINE0_6               (0xff<<16)
+
+
+#define CABC_GAUSS_LINE1_0             (0x01d0)
+#define v_CABC_T_LINE1_0(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE1_1(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE1_2(x)            (((x)&0xff)<<16)
+#define v_CABC_T_LINE1_3(x)            (((x)&0xff)<<24)
+#define m_CABC_T_LINE1_0               (0xff<<0)
+#define m_CABC_T_LINE1_1               (0xff<<8)
+#define m_CABC_T_LINE1_2               (0xff<<16)
+#define m_CABC_T_LINE1_3               ((u32)0xff<<24)
+
+#define CABC_GAUSS_LINE1_1             (0x01d4)
+#define v_CABC_T_LINE1_4(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE1_5(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE1_6(x)            (((x)&0xff)<<16)
+#define m_CABC_T_LINE1_4               (0xff<<0)
+#define m_CABC_T_LINE1_5               (0xff<<8)
+#define m_CABC_T_LINE1_6               (0xff<<16)
+
+#define CABC_GAUSS_LINE2_0             (0x01d8)
+#define v_CABC_T_LINE2_0(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE2_1(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE2_2(x)            (((x)&0xff)<<16)
+#define v_CABC_T_LINE2_3(x)            (((x)&0xff)<<24)
+#define m_CABC_T_LINE2_0               (0xff<<0)
+#define m_CABC_T_LINE2_1               (0xff<<8)
+#define m_CABC_T_LINE2_2               (0xff<<16)
+#define m_CABC_T_LINE2_3               ((u32)0xff<<24)
+
+#define CABC_GAUSS_LINE2_1             (0x01dc)
+#define v_CABC_T_LINE2_4(x)            (((x)&0xff)<<0)
+#define v_CABC_T_LINE2_5(x)            (((x)&0xff)<<8)
+#define v_CABC_T_LINE2_6(x)            (((x)&0xff)<<16)
+#define m_CABC_T_LINE2_4               (0xff<<0)
+#define m_CABC_T_LINE2_5               (0xff<<8)
+#define m_CABC_T_LINE2_6               (0xff<<16)
+
+/*FRC register*/
+#define FRC_LOWER01_0                  (0x01e0)
+#define v_FRC_LOWER01_FRM0(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER01_FRM1(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER01_FRM0             (0xffff<<0)
+#define m_FRC_LOWER01_FRM1             ((u32)0xffff<<16)
+
+#define FRC_LOWER01_1                  (0x01e4)
+#define v_FRC_LOWER01_FRM2(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER01_FRM3(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER01_FRM2             (0xffff<<0)
+#define m_FRC_LOWER01_FRM3             ((u32)0xffff<<16)
+
+#define FRC_LOWER10_0                  (0x01e8)
+#define v_FRC_LOWER10_FRM0(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER10_FRM1(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER10_FRM0             (0xffff<<0)
+#define m_FRC_LOWER10_FRM1             ((u32)0xffff<<16)
+
+#define FRC_LOWER10_1                  (0x01ec)
+#define v_FRC_LOWER10_FRM2(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER10_FRM3(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER10_FRM2             (0xffff<<0)
+#define m_FRC_LOWER10_FRM3             ((u32)0xffff<<16)
+
+#define FRC_LOWER11_0                  (0x01f0)
+#define v_FRC_LOWER11_FRM0(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER11_FRM1(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER11_FRM0             (0xffff<<0)
+#define m_FRC_LOWER11_FRM1             ((u32)0xffff<<16)
+
+#define FRC_LOWER11_1                  (0x01f4)
+#define v_FRC_LOWER11_FRM2(x)          (((x)&0xffff)<<0)
+#define v_FRC_LOWER11_FRM3(x)          (((x)&0xffff)<<16)
+#define m_FRC_LOWER11_FRM2             (0xffff<<0)
+#define m_FRC_LOWER11_FRM3             ((u32)0xffff<<16)
+
+#define MMU_DTE_ADDR                   (0x0300)
+#define v_MMU_DTE_ADDR(x)              (((x)&0xffffffff)<<0)
+#define m_MMU_DTE_ADDR                 (0xffffffff<<0)
+
+#define MMU_STATUS                     (0x0304)
+#define v_PAGING_ENABLED(x)            (((x)&1)<<0)
+#define v_PAGE_FAULT_ACTIVE(x)         (((x)&1)<<1)
+#define v_STAIL_ACTIVE(x)              (((x)&1)<<2)
+#define v_MMU_IDLE(x)                  (((x)&1)<<3)
+#define v_REPLAY_BUFFER_EMPTY(x)       (((x)&1)<<4)
+#define v_PAGE_FAULT_IS_WRITE(x)       (((x)&1)<<5)
+#define v_PAGE_FAULT_BUS_ID(x)         (((x)&0x1f)<<6)
+#define m_PAGING_ENABLED               (1<<0)
+#define m_PAGE_FAULT_ACTIVE            (1<<1)
+#define m_STAIL_ACTIVE                 (1<<2)
+#define m_MMU_IDLE                     (1<<3)
+#define m_REPLAY_BUFFER_EMPTY          (1<<4)
+#define m_PAGE_FAULT_IS_WRITE          (1<<5)
+#define m_PAGE_FAULT_BUS_ID            (0x1f<<6)
+
+#define MMU_COMMAND                    (0x0308)
+#define v_MMU_CMD(x)                   (((x)&0x3)<<0)
+#define m_MMU_CMD                      (0x3<<0)
+
+#define MMU_PAGE_FAULT_ADDR            (0x030c)
+#define v_PAGE_FAULT_ADDR(x)           (((x)&0xffffffff)<<0)
+#define m_PAGE_FAULT_ADDR              (0xffffffff<<0)
+
+#define MMU_ZAP_ONE_LINE               (0x0310)
+#define v_MMU_ZAP_ONE_LINE(x)          (((x)&0xffffffff)<<0)
+#define m_MMU_ZAP_ONE_LINE             (0xffffffff<<0)
+
+#define MMU_INT_RAWSTAT                        (0x0314)
+#define v_PAGE_FAULT_RAWSTAT(x)                (((x)&1)<<0)
+#define v_READ_BUS_ERROR_RAWSTAT(x)    (((x)&1)<<1)
+#define m_PAGE_FAULT_RAWSTAT           (1<<0)
+#define m_READ_BUS_ERROR_RAWSTAT       (1<<1)
+
+#define MMU_INT_CLEAR                  (0x0318)
+#define v_PAGE_FAULT_CLEAR(x)          (((x)&1)<<0)
+#define v_READ_BUS_ERROR_CLEAR(x)      (((x)&1)<<1)
+#define m_PAGE_FAULT_CLEAR             (1<<0)
+#define m_READ_BUS_ERROR_CLEAR         (1<<1)
+
+#define MMU_INT_MASK                   (0x031c)
+#define v_PAGE_FAULT_MASK(x)           (((x)&1)<<0)
+#define v_READ_BUS_ERROR_MASK(x)       (((x)&1)<<1)
+#define m_PAGE_FAULT_MASK              (1<<0)
+#define m_READ_BUS_ERROR_MASK          (1<<1)
+
+#define MMU_INT_STATUS                 (0x0320)
+#define v_PAGE_FAULT_STATUS(x)         (((x)&1)<<0)
+#define v_READ_BUS_ERROR_STATUS(x)     (((x)&1)<<1)
+#define m_PAGE_FAULT_STATUS            (1<<0)
+#define m_READ_BUS_ERROR_STATUS                (1<<1)
+
+#define MMU_AUTO_GATING                        (0x0324)
+#define v_MMU_AUTO_GATING(x)           (((x)&1)<<0)
+#define m_MMU_AUTO_GATING              (1<<0)
+
+#define WIN2_LUT_ADDR                  (0x0400)
+#define WIN3_LUT_ADDR                          (0x0800)
+#define HWC_LUT_ADDR                           (0x0c00)
+#define GAMMA_LUT_ADDR                         (0x1000)
+#define MCU_BYPASS_WPORT               (0x2200) 
+#define MCU_BYPASS_RPORT               (0x2300)
+
+#define PWM_MODE_ONE_SHOT              (0x0)
+#define PWM_MODE_CONTINUOUS            (0x1)
+#define PWM_MODE_CAPTURE               (0x2)
+//#endif
+
+
+#define CalScale(x, y)              ((((u32)(x-1))*0x1000)/(y-1))
+
+
+
+/*ALPHA BLENDING MODE*/
+enum alpha_mode {               /*  Fs       Fd */
+       AB_USER_DEFINE     = 0x0,
+       AB_CLEAR           = 0x1,/*  0          0*/
+       AB_SRC             = 0x2,/*  1          0*/
+       AB_DST             = 0x3,/*  0          1  */
+       AB_SRC_OVER        = 0x4,/*  1              1-As''*/
+       AB_DST_OVER        = 0x5,/*  1-Ad''   1*/
+       AB_SRC_IN          = 0x6,
+       AB_DST_IN          = 0x7,
+       AB_SRC_OUT         = 0x8,
+       AB_DST_OUT         = 0x9,
+       AB_SRC_ATOP        = 0xa,
+       AB_DST_ATOP        = 0xb,
+       XOR                = 0xc,
+       AB_SRC_OVER_GLOBAL = 0xd
+}; /*alpha_blending_mode*/
+
+enum src_alpha_mode {
+       AA_STRAIGHT        = 0x0,
+       AA_INVERSE         = 0x1
+};/*src_alpha_mode*/
+
+enum global_alpha_mode {
+       AA_GLOBAL         = 0x0,
+       AA_PER_PIX        = 0x1,
+       AA_PER_PIX_GLOBAL = 0x2
+};/*src_global_alpha_mode*/
+
+enum src_alpha_sel {
+       AA_SAT          = 0x0,
+       AA_NO_SAT       = 0x1
+};/*src_alpha_sel*/
+
+enum src_color_mode {
+       AA_SRC_PRE_MUL         = 0x0,
+       AA_SRC_NO_PRE_MUL      = 0x1
+};/*src_color_mode*/
+
+enum factor_mode {
+       AA_ZERO                 = 0x0,
+       AA_ONE                  = 0x1,
+       AA_SRC                  = 0x2,
+       AA_SRC_INVERSE          = 0x3,
+       AA_SRC_GLOBAL           = 0x4
+};/*src_factor_mode  &&  dst_factor_mode*/
+struct alpha_config{
+       enum src_alpha_mode src_alpha_mode;       /*win0_src_alpha_m0*/
+       u32 src_global_alpha_val; /*win0_src_global_alpha*/
+       enum global_alpha_mode src_global_alpha_mode;/*win0_src_blend_m0*/
+       enum src_alpha_sel src_alpha_cal_m0;     /*win0_src_alpha_cal_m0*/
+       enum src_color_mode src_color_mode;      /*win0_src_color_m0*/
+       enum factor_mode src_factor_mode;        /*win0_src_factor_m0*/
+       enum factor_mode dst_factor_mode;      /*win0_dst_factor_m0*/
+};
+
+
+static inline void lcdc_writel(struct fimd_context *ctx,u32 offset,u32 v)
+{
+       u32 *_pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);   
+       *_pv = v;
+       writel_relaxed(v,ctx->regs+offset);     
+}
+
+static inline u32 lcdc_readl(struct fimd_context *ctx,u32 offset)
+{
+       u32 v;
+       u32 *_pv = (u32*)ctx->regsbak;
+       _pv += (offset >> 2);
+       v = readl_relaxed(ctx->regs+offset);
+       *_pv = v;
+       return v;
+}
+
+static inline u32 lcdc_read_bit(struct fimd_context *ctx,u32 offset,u32 msk) 
+{
+       u32 _v = readl_relaxed(ctx->regs+offset); 
+       _v &= msk;
+       return (_v >> msk);   
+}
+
+static inline void  lcdc_set_bit(struct fimd_context *ctx,u32 offset,u32 msk) 
+{
+       u32* _pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                           
+       (*_pv) |= msk;                          
+       writel_relaxed(*_pv,ctx->regs + offset); 
+} 
+
+static inline void lcdc_clr_bit(struct fimd_context *ctx,u32 offset,u32 msk)
+{
+       u32* _pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                           
+       (*_pv) &= (~msk);                               
+       writel_relaxed(*_pv,ctx->regs + offset); 
+} 
+
+static inline void  lcdc_msk_reg(struct fimd_context *ctx,u32 offset,u32 msk,u32 v)
+{
+       u32 *_pv = (u32*)ctx->regsbak;  
+       _pv += (offset >> 2);                   
+       (*_pv) &= (~msk);                               
+       (*_pv) |= v;                            
+       writel_relaxed(*_pv,ctx->regs+offset);  
+}
+
+static inline void lcdc_cfg_done(struct fimd_context *ctx) 
+{
+       writel_relaxed(0x01,ctx->regs+REG_CFG_DONE); 
+       dsb();  
+} 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_buf.c b/drivers/gpu/drm/rockchip/rockchip_drm_buf.c
new file mode 100644 (file)
index 0000000..3e1fa16
--- /dev/null
@@ -0,0 +1,203 @@
+/* rockchip_drm_buf.c
+ *
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_buf.h"
+#include "rockchip_drm_iommu.h"
+
+static int lowlevel_buffer_allocate(struct drm_device *dev,
+               unsigned int flags, struct rockchip_drm_gem_buf *buf)
+{
+       int ret = 0;
+       enum dma_attr attr;
+       unsigned int nr_pages;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (buf->dma_addr) {
+               DRM_DEBUG_KMS("already allocated.\n");
+               return 0;
+       }
+
+       init_dma_attrs(&buf->dma_attrs);
+
+       /*
+        * if ROCKCHIP_BO_CONTIG, fully physically contiguous memory
+        * region will be allocated else physically contiguous
+        * as possible.
+        */
+       if (!(flags & ROCKCHIP_BO_NONCONTIG))
+               dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
+
+       /*
+        * if ROCKCHIP_BO_WC or ROCKCHIP_BO_NONCACHABLE, writecombine mapping
+        * else cachable mapping.
+        */
+       if (flags & ROCKCHIP_BO_WC || !(flags & ROCKCHIP_BO_CACHABLE))
+               attr = DMA_ATTR_WRITE_COMBINE;
+       else
+               attr = DMA_ATTR_NON_CONSISTENT;
+
+       dma_set_attr(attr, &buf->dma_attrs);
+       dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
+
+       nr_pages = buf->size >> PAGE_SHIFT;
+
+       if (!is_drm_iommu_supported(dev)) {
+               dma_addr_t start_addr;
+               unsigned int i = 0;
+
+               buf->pages = kzalloc(sizeof(struct page) * nr_pages,
+                                       GFP_KERNEL);
+               if (!buf->pages) {
+                       DRM_ERROR("failed to allocate pages.\n");
+                       return -ENOMEM;
+               }
+
+               buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
+                                       &buf->dma_addr, GFP_KERNEL,
+                                       &buf->dma_attrs);
+               if (!buf->kvaddr) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       kfree(buf->pages);
+                       return -ENOMEM;
+               }
+
+               start_addr = buf->dma_addr;
+               while (i < nr_pages) {
+                       buf->pages[i] = phys_to_page(start_addr);
+                       start_addr += PAGE_SIZE;
+                       i++;
+               }
+       } else {
+
+               buf->pages = dma_alloc_attrs(dev->dev, buf->size,
+                                       &buf->dma_addr, GFP_KERNEL,
+                                       &buf->dma_attrs);
+               if (!buf->pages) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       return -ENOMEM;
+               }
+       }
+
+       buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
+       if (!buf->sgt) {
+               DRM_ERROR("failed to get sg table.\n");
+               ret = -ENOMEM;
+               goto err_free_attrs;
+       }
+
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+                       (unsigned long)buf->dma_addr,
+                       buf->size);
+
+       return ret;
+
+err_free_attrs:
+       dma_free_attrs(dev->dev, buf->size, buf->pages,
+                       (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+       buf->dma_addr = (dma_addr_t)NULL;
+
+       if (!is_drm_iommu_supported(dev))
+               kfree(buf->pages);
+
+       return ret;
+}
+
+static void lowlevel_buffer_deallocate(struct drm_device *dev,
+               unsigned int flags, struct rockchip_drm_gem_buf *buf)
+{
+       DRM_DEBUG_KMS("%s.\n", __FILE__);
+
+       if (!buf->dma_addr) {
+               DRM_DEBUG_KMS("dma_addr is invalid.\n");
+               return;
+       }
+
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+                       (unsigned long)buf->dma_addr,
+                       buf->size);
+
+       sg_free_table(buf->sgt);
+
+       kfree(buf->sgt);
+       buf->sgt = NULL;
+
+       if (!is_drm_iommu_supported(dev)) {
+               dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+                               (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+               kfree(buf->pages);
+       } else
+               dma_free_attrs(dev->dev, buf->size, buf->pages,
+                               (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+
+       buf->dma_addr = (dma_addr_t)NULL;
+}
+
+struct rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
+                                               unsigned int size)
+{
+       struct rockchip_drm_gem_buf *buffer;
+
+       DRM_DEBUG_KMS("%s.\n", __FILE__);
+       DRM_DEBUG_KMS("desired size = 0x%x\n", size);
+
+       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+       if (!buffer) {
+               DRM_ERROR("failed to allocate rockchip_drm_gem_buf.\n");
+               return NULL;
+       }
+
+       buffer->size = size;
+       return buffer;
+}
+
+void rockchip_drm_fini_buf(struct drm_device *dev,
+                               struct rockchip_drm_gem_buf *buffer)
+{
+       DRM_DEBUG_KMS("%s.\n", __FILE__);
+
+       if (!buffer) {
+               DRM_DEBUG_KMS("buffer is null.\n");
+               return;
+       }
+
+       kfree(buffer);
+       buffer = NULL;
+}
+
+int rockchip_drm_alloc_buf(struct drm_device *dev,
+               struct rockchip_drm_gem_buf *buf, unsigned int flags)
+{
+
+       /*
+        * allocate memory region and set the memory information
+        * to vaddr and dma_addr of a buffer object.
+        */
+       if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void rockchip_drm_free_buf(struct drm_device *dev,
+               unsigned int flags, struct rockchip_drm_gem_buf *buffer)
+{
+
+       lowlevel_buffer_deallocate(dev, flags, buffer);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_buf.h b/drivers/gpu/drm/rockchip/rockchip_drm_buf.h
new file mode 100644 (file)
index 0000000..ed246f7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_BUF_H_
+#define _ROCKCHIP_DRM_BUF_H_
+
+/* create and initialize buffer object. */
+struct rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
+                                               unsigned int size);
+
+/* destroy buffer object. */
+void rockchip_drm_fini_buf(struct drm_device *dev,
+                               struct rockchip_drm_gem_buf *buffer);
+
+/* allocate physical memory region and setup sgt. */
+int rockchip_drm_alloc_buf(struct drm_device *dev,
+                               struct rockchip_drm_gem_buf *buf,
+                               unsigned int flags);
+
+/* release physical memory region, and sgt. */
+void rockchip_drm_free_buf(struct drm_device *dev,
+                               unsigned int flags,
+                               struct rockchip_drm_gem_buf *buffer);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.c b/drivers/gpu/drm/rockchip/rockchip_drm_connector.c
new file mode 100644 (file)
index 0000000..c3d5119
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <drm/rockchip_drm.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+
+#define to_rockchip_connector(x)       container_of(x, struct rockchip_drm_connector,\
+                               drm_connector)
+
+struct rockchip_drm_connector {
+       struct drm_connector    drm_connector;
+       uint32_t                encoder_id;
+       struct rockchip_drm_manager *manager;
+       uint32_t                dpms;
+};
+
+/* convert rockchip_video_timings to drm_display_mode */
+static inline void
+convert_to_display_mode(struct drm_display_mode *mode,
+                       struct rockchip_drm_panel_info *panel)
+{
+       struct fb_videomode *timing = &panel->timing;
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       mode->clock = timing->pixclock / 1000;
+       mode->vrefresh = timing->refresh;
+
+       mode->hdisplay = timing->xres;
+       mode->hsync_start = mode->hdisplay + timing->right_margin;
+       mode->hsync_end = mode->hsync_start + timing->hsync_len;
+       mode->htotal = mode->hsync_end + timing->left_margin;
+
+       mode->vdisplay = timing->yres;
+       mode->vsync_start = mode->vdisplay + timing->lower_margin;
+       mode->vsync_end = mode->vsync_start + timing->vsync_len;
+       mode->vtotal = mode->vsync_end + timing->upper_margin;
+       mode->width_mm = panel->width_mm;
+       mode->height_mm = panel->height_mm;
+
+       if (timing->vmode & FB_VMODE_INTERLACED)
+               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+       if (timing->vmode & FB_VMODE_DOUBLE)
+               mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+}
+
+/* convert drm_display_mode to rockchip_video_timings */
+static inline void
+convert_to_video_timing(struct fb_videomode *timing,
+                       struct drm_display_mode *mode)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       memset(timing, 0, sizeof(*timing));
+
+       timing->pixclock = mode->clock * 1000;
+       timing->refresh = drm_mode_vrefresh(mode);
+
+       timing->xres = mode->hdisplay;
+       timing->right_margin = mode->hsync_start - mode->hdisplay;
+       timing->hsync_len = mode->hsync_end - mode->hsync_start;
+       timing->left_margin = mode->htotal - mode->hsync_end;
+
+       timing->yres = mode->vdisplay;
+       timing->lower_margin = mode->vsync_start - mode->vdisplay;
+       timing->vsync_len = mode->vsync_end - mode->vsync_start;
+       timing->upper_margin = mode->vtotal - mode->vsync_end;
+
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               timing->vmode = FB_VMODE_INTERLACED;
+       else
+               timing->vmode = FB_VMODE_NONINTERLACED;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               timing->vmode |= FB_VMODE_DOUBLE;
+}
+
+static int rockchip_drm_connector_get_modes(struct drm_connector *connector)
+{
+       struct rockchip_drm_connector *rockchip_connector =
+                                       to_rockchip_connector(connector);
+       struct rockchip_drm_manager *manager = rockchip_connector->manager;
+       struct rockchip_drm_display_ops *display_ops = manager->display_ops;
+       struct edid *edid = NULL;
+       unsigned int count = 0;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!display_ops) {
+               DRM_DEBUG_KMS("display_ops is null.\n");
+               return 0;
+       }
+
+       /*
+        * if get_edid() exists then get_edid() callback of hdmi side
+        * is called to get edid data through i2c interface else
+        * get timing from the FIMD driver(display controller).
+        *
+        * P.S. in case of lcd panel, count is always 1 if success
+        * because lcd panel has only one mode.
+        */
+       if (display_ops->get_edid) {
+               edid = display_ops->get_edid(manager->dev, connector);
+               if (IS_ERR_OR_NULL(edid)) {
+                       ret = PTR_ERR(edid);
+                       edid = NULL;
+                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
+                       goto out;
+               }
+
+               count = drm_add_edid_modes(connector, edid);
+               if (!count) {
+                       DRM_ERROR("Add edid modes failed %d\n", count);
+                       goto out;
+               }
+
+               drm_mode_connector_update_edid_property(connector, edid);
+       } else {
+               struct rockchip_drm_panel_info *panel;
+               struct drm_display_mode *mode = drm_mode_create(connector->dev);
+               if (!mode) {
+                       DRM_ERROR("failed to create a new display mode.\n");
+                       return 0;
+               }
+
+               if (display_ops->get_panel)
+                       panel = display_ops->get_panel(manager->dev);
+               else {
+                       drm_mode_destroy(connector->dev, mode);
+                       return 0;
+               }
+
+               convert_to_display_mode(mode, panel);
+               connector->display_info.width_mm = mode->width_mm;
+               connector->display_info.height_mm = mode->height_mm;
+
+               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+               drm_mode_set_name(mode);
+               drm_mode_probed_add(connector, mode);
+
+               count = 1;
+       }
+
+out:
+       kfree(edid);
+       return count;
+}
+
+static int rockchip_drm_connector_mode_valid(struct drm_connector *connector,
+                                           struct drm_display_mode *mode)
+{
+       struct rockchip_drm_connector *rockchip_connector =
+                                       to_rockchip_connector(connector);
+       struct rockchip_drm_manager *manager = rockchip_connector->manager;
+       struct rockchip_drm_display_ops *display_ops = manager->display_ops;
+       struct fb_videomode timing;
+       int ret = MODE_BAD;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       convert_to_video_timing(&timing, mode);
+
+       if (display_ops && display_ops->check_timing)
+               if (!display_ops->check_timing(manager->dev, (void *)&timing))
+                       ret = MODE_OK;
+
+       return ret;
+}
+
+struct drm_encoder *rockchip_drm_best_encoder(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct rockchip_drm_connector *rockchip_connector =
+                                       to_rockchip_connector(connector);
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       obj = drm_mode_object_find(dev, rockchip_connector->encoder_id,
+                                  DRM_MODE_OBJECT_ENCODER);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
+                               rockchip_connector->encoder_id);
+               return NULL;
+       }
+
+       encoder = obj_to_encoder(obj);
+
+       return encoder;
+}
+
+static struct drm_connector_helper_funcs rockchip_connector_helper_funcs = {
+       .get_modes      = rockchip_drm_connector_get_modes,
+       .mode_valid     = rockchip_drm_connector_mode_valid,
+       .best_encoder   = rockchip_drm_best_encoder,
+};
+
+void rockchip_drm_display_power(struct drm_connector *connector, int mode)
+{
+       struct drm_encoder *encoder = rockchip_drm_best_encoder(connector);
+       struct rockchip_drm_connector *rockchip_connector;
+       struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
+       struct rockchip_drm_display_ops *display_ops = manager->display_ops;
+
+       rockchip_connector = to_rockchip_connector(connector);
+
+       if (rockchip_connector->dpms == mode) {
+               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+               return;
+       }
+
+       if (display_ops && display_ops->power_on)
+               display_ops->power_on(manager->dev, mode);
+
+       rockchip_connector->dpms = mode;
+}
+
+static void rockchip_drm_connector_dpms(struct drm_connector *connector,
+                                       int mode)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * in case that drm_crtc_helper_set_mode() is called,
+        * encoder/crtc->funcs->dpms() will be just returned
+        * because they already were DRM_MODE_DPMS_ON so only
+        * rockchip_drm_display_power() will be called.
+        */
+       drm_helper_connector_dpms(connector, mode);
+
+       rockchip_drm_display_power(connector, mode);
+
+}
+
+static int rockchip_drm_connector_fill_modes(struct drm_connector *connector,
+                               unsigned int max_width, unsigned int max_height)
+{
+       struct rockchip_drm_connector *rockchip_connector =
+                                       to_rockchip_connector(connector);
+       struct rockchip_drm_manager *manager = rockchip_connector->manager;
+       struct rockchip_drm_manager_ops *ops = manager->ops;
+       unsigned int width, height;
+
+       width = max_width;
+       height = max_height;
+
+       /*
+        * if specific driver want to find desired_mode using maxmum
+        * resolution then get max width and height from that driver.
+        */
+       if (ops && ops->get_max_resol)
+               ops->get_max_resol(manager->dev, &width, &height);
+
+       return drm_helper_probe_single_connector_modes(connector, width,
+                                                       height);
+}
+
+/* get detection status of display device. */
+static enum drm_connector_status
+rockchip_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct rockchip_drm_connector *rockchip_connector =
+                                       to_rockchip_connector(connector);
+       struct rockchip_drm_manager *manager = rockchip_connector->manager;
+       struct rockchip_drm_display_ops *display_ops =
+                                       manager->display_ops;
+       enum drm_connector_status status = connector_status_disconnected;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (display_ops && display_ops->is_connected) {
+               if (display_ops->is_connected(manager->dev))
+                       status = connector_status_connected;
+               else
+                       status = connector_status_disconnected;
+       }
+
+       return status;
+}
+
+static void rockchip_drm_connector_destroy(struct drm_connector *connector)
+{
+       struct rockchip_drm_connector *rockchip_connector =
+               to_rockchip_connector(connector);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(rockchip_connector);
+}
+
+static struct drm_connector_funcs rockchip_connector_funcs = {
+       .dpms           = rockchip_drm_connector_dpms,
+       .fill_modes     = rockchip_drm_connector_fill_modes,
+       .detect         = rockchip_drm_connector_detect,
+       .destroy        = rockchip_drm_connector_destroy,
+};
+
+struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
+                                                  struct drm_encoder *encoder)
+{
+       struct rockchip_drm_connector *rockchip_connector;
+       struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
+       struct drm_connector *connector;
+       int type;
+       int err;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_connector = kzalloc(sizeof(*rockchip_connector), GFP_KERNEL);
+       if (!rockchip_connector) {
+               DRM_ERROR("failed to allocate connector\n");
+               return NULL;
+       }
+
+       connector = &rockchip_connector->drm_connector;
+
+       switch (manager->display_ops->type) {
+       case ROCKCHIP_DISPLAY_TYPE_HDMI:
+               type = DRM_MODE_CONNECTOR_HDMIA;
+               connector->interlace_allowed = true;
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
+               break;
+       case ROCKCHIP_DISPLAY_TYPE_VIDI:
+               type = DRM_MODE_CONNECTOR_VIRTUAL;
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
+               break;
+       case ROCKCHIP_DISPLAY_TYPE_LCD:
+               type = DRM_MODE_CONNECTOR_LVDS;
+               break;
+       default:
+               type = DRM_MODE_CONNECTOR_Unknown;
+               break;
+       }
+
+       drm_connector_init(dev, connector, &rockchip_connector_funcs, type);
+       drm_connector_helper_add(connector, &rockchip_connector_helper_funcs);
+
+       err = drm_sysfs_connector_add(connector);
+       if (err)
+               goto err_connector;
+
+       rockchip_connector->encoder_id = encoder->base.id;
+       rockchip_connector->manager = manager;
+       rockchip_connector->dpms = DRM_MODE_DPMS_OFF;
+       connector->dpms = DRM_MODE_DPMS_OFF;
+       connector->encoder = encoder;
+
+       err = drm_mode_connector_attach_encoder(connector, encoder);
+       if (err) {
+               DRM_ERROR("failed to attach a connector to a encoder\n");
+               goto err_sysfs;
+       }
+
+       DRM_DEBUG_KMS("connector has been created\n");
+
+       return connector;
+
+err_sysfs:
+       drm_sysfs_connector_remove(connector);
+err_connector:
+       drm_connector_cleanup(connector);
+       kfree(rockchip_connector);
+       return NULL;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.h b/drivers/gpu/drm/rockchip/rockchip_drm_connector.h
new file mode 100644 (file)
index 0000000..bba1846
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_CONNECTOR_H_
+#define _ROCKCHIP_DRM_CONNECTOR_H_
+
+struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
+                                                  struct drm_encoder *encoder);
+
+struct drm_encoder *rockchip_drm_best_encoder(struct drm_connector *connector);
+
+void rockchip_drm_display_power(struct drm_connector *connector, int mode);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_core.c b/drivers/gpu/drm/rockchip/rockchip_drm_core.c
new file mode 100644 (file)
index 0000000..3e9b946
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_connector.h"
+#include "rockchip_drm_fbdev.h"
+
+static LIST_HEAD(rockchip_drm_subdrv_list);
+
+static int rockchip_drm_create_enc_conn(struct drm_device *dev,
+                                       struct rockchip_drm_subdrv *subdrv)
+{
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       int ret;
+
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       subdrv->manager->dev = subdrv->dev;
+
+       /* create and initialize a encoder for this sub driver. */
+       encoder = rockchip_drm_encoder_create(dev, subdrv->manager,
+                       (1 << MAX_CRTC) - 1);
+       if (!encoder) {
+               DRM_ERROR("failed to create encoder\n");
+               return -EFAULT;
+       }
+
+       /*
+        * create and initialize a connector for this sub driver and
+        * attach the encoder created above to the connector.
+        */
+       connector = rockchip_drm_connector_create(dev, encoder);
+       if (!connector) {
+               DRM_ERROR("failed to create connector\n");
+               ret = -EFAULT;
+               goto err_destroy_encoder;
+       }
+
+       subdrv->encoder = encoder;
+       subdrv->connector = connector;
+
+       return 0;
+
+err_destroy_encoder:
+       encoder->funcs->destroy(encoder);
+       return ret;
+}
+
+static void rockchip_drm_destroy_enc_conn(struct rockchip_drm_subdrv *subdrv)
+{
+       if (subdrv->encoder) {
+               struct drm_encoder *encoder = subdrv->encoder;
+               encoder->funcs->destroy(encoder);
+               subdrv->encoder = NULL;
+       }
+
+       if (subdrv->connector) {
+               struct drm_connector *connector = subdrv->connector;
+               connector->funcs->destroy(connector);
+               subdrv->connector = NULL;
+       }
+}
+
+static int rockchip_drm_subdrv_probe(struct drm_device *dev,
+                                       struct rockchip_drm_subdrv *subdrv)
+{
+       if (subdrv->probe) {
+               int ret;
+
+               subdrv->drm_dev = dev;
+
+               /*
+                * this probe callback would be called by sub driver
+                * after setting of all resources to this sub driver,
+                * such as clock, irq and register map are done or by load()
+                * of rockchip drm driver.
+                *
+                * P.S. note that this driver is considered for modularization.
+                */
+               ret = subdrv->probe(dev, subdrv->dev);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void rockchip_drm_subdrv_remove(struct drm_device *dev,
+                                     struct rockchip_drm_subdrv *subdrv)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       if (subdrv->remove)
+               subdrv->remove(dev, subdrv->dev);
+}
+
+int rockchip_drm_device_register(struct drm_device *dev)
+{
+       struct rockchip_drm_subdrv *subdrv, *n;
+       unsigned int fine_cnt = 0;
+       int err;
+
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       if (!dev)
+               return -EINVAL;
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       list_for_each_entry_safe(subdrv, n, &rockchip_drm_subdrv_list, list) {
+               err = rockchip_drm_subdrv_probe(dev, subdrv);
+               if (err) {
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+                       DRM_DEBUG("rockchip drm subdrv probe failed.\n");
+                       list_del(&subdrv->list);
+                       continue;
+               }
+
+               /*
+                * if manager is null then it means that this sub driver
+                * doesn't need encoder and connector.
+                */
+               if (!subdrv->manager) {
+                       fine_cnt++;
+                       continue;
+               }
+
+               err = rockchip_drm_create_enc_conn(dev, subdrv);
+               if (err) {
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+                       DRM_DEBUG("failed to create encoder and connector.\n");
+                       rockchip_drm_subdrv_remove(dev, subdrv);
+                       list_del(&subdrv->list);
+                       continue;
+               }
+
+               fine_cnt++;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       if (!fine_cnt)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_device_register);
+
+int rockchip_drm_device_unregister(struct drm_device *dev)
+{
+       struct rockchip_drm_subdrv *subdrv;
+
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       if (!dev) {
+               WARN(1, "Unexpected drm device unregister!\n");
+               return -EINVAL;
+       }
+
+       list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+               rockchip_drm_subdrv_remove(dev, subdrv);
+               rockchip_drm_destroy_enc_conn(subdrv);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_device_unregister);
+
+int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *subdrv)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       if (!subdrv)
+               return -EINVAL;
+
+       list_add_tail(&subdrv->list, &rockchip_drm_subdrv_list);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_register);
+
+int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *subdrv)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       if (!subdrv)
+               return -EINVAL;
+
+       list_del(&subdrv->list);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_unregister);
+
+int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
+{
+       struct rockchip_drm_subdrv *subdrv;
+       int ret;
+
+       list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+               if (subdrv->open) {
+                       ret = subdrv->open(dev, subdrv->dev, file);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
+               if (subdrv->close)
+                       subdrv->close(dev, subdrv->dev, file);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_open);
+
+void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
+{
+       struct rockchip_drm_subdrv *subdrv;
+
+       list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+               if (subdrv->close)
+                       subdrv->close(dev, subdrv->dev, file);
+       }
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_close);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_crtc.c b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
new file mode 100644 (file)
index 0000000..90b3ea9
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_plane.h"
+
+#define to_rockchip_crtc(x)    container_of(x, struct rockchip_drm_crtc,\
+                               drm_crtc)
+
+enum rockchip_crtc_mode {
+       CRTC_MODE_NORMAL,       /* normal mode */
+       CRTC_MODE_BLANK,        /* The private plane of crtc is blank */
+};
+
+/*
+ * Exynos specific crtc structure.
+ *
+ * @drm_crtc: crtc object.
+ * @drm_plane: pointer of private plane object for this crtc
+ * @pipe: a crtc index created at load() with a new crtc object creation
+ *     and the crtc object would be set to private->crtc array
+ *     to get a crtc object corresponding to this pipe from private->crtc
+ *     array when irq interrupt occured. the reason of using this pipe is that
+ *     drm framework doesn't support multiple irq yet.
+ *     we can refer to the crtc to current hardware interrupt occured through
+ *     this pipe value.
+ * @dpms: store the crtc dpms value
+ * @mode: store the crtc mode value
+ */
+struct rockchip_drm_crtc {
+       struct drm_crtc                 drm_crtc;
+       struct drm_plane                *plane;
+       unsigned int                    pipe;
+       unsigned int                    dpms;
+       enum rockchip_crtc_mode         mode;
+       wait_queue_head_t               pending_flip_queue;
+       atomic_t                        pending_flip;
+};
+
+static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+
+       DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
+
+       if (rockchip_crtc->dpms == mode) {
+               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+               return;
+       }
+
+       if (mode > DRM_MODE_DPMS_ON) {
+               /* wait for the completion of page flip. */
+               wait_event(rockchip_crtc->pending_flip_queue,
+                               atomic_read(&rockchip_crtc->pending_flip) == 0);
+               drm_vblank_off(crtc->dev, rockchip_crtc->pipe);
+       }
+
+       rockchip_drm_fn_encoder(crtc, &mode, rockchip_drm_encoder_crtc_dpms);
+       rockchip_crtc->dpms = mode;
+}
+
+static void rockchip_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* drm framework doesn't check NULL. */
+}
+
+static void rockchip_drm_crtc_commit(struct drm_crtc *crtc)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       rockchip_plane_commit(rockchip_crtc->plane);
+       rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_ON);
+}
+
+static bool
+rockchip_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+                           const struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* drm framework doesn't check NULL */
+       return true;
+}
+
+static int
+rockchip_drm_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)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+       struct drm_plane *plane = rockchip_crtc->plane;
+       unsigned int crtc_w;
+       unsigned int crtc_h;
+       int pipe = rockchip_crtc->pipe;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * copy the mode data adjusted by mode_fixup() into crtc->mode
+        * so that hardware can be seet to proper mode.
+        */
+       memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
+
+       crtc_w = crtc->fb->width - x;
+       crtc_h = crtc->fb->height - y;
+
+       ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+                                   x, y, crtc_w, crtc_h);
+       if (ret)
+               return ret;
+
+       plane->crtc = crtc;
+       plane->fb = crtc->fb;
+
+       rockchip_drm_fn_encoder(crtc, &pipe, rockchip_drm_encoder_crtc_pipe);
+
+       return 0;
+}
+
+static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                         struct drm_framebuffer *old_fb)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+       struct drm_plane *plane = rockchip_crtc->plane;
+       unsigned int crtc_w;
+       unsigned int crtc_h;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* when framebuffer changing is requested, crtc's dpms should be on */
+       if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
+               DRM_ERROR("failed framebuffer changing request.\n");
+               return -EPERM;
+       }
+
+       crtc_w = crtc->fb->width - x;
+       crtc_h = crtc->fb->height - y;
+
+       ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+                                   x, y, crtc_w, crtc_h);
+       if (ret)
+               return ret;
+
+       rockchip_drm_crtc_commit(crtc);
+
+       return 0;
+}
+
+static void rockchip_drm_crtc_load_lut(struct drm_crtc *crtc)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+       /* drm framework doesn't check NULL */
+}
+
+static void rockchip_drm_crtc_disable(struct drm_crtc *crtc)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_OFF);
+       rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static struct drm_crtc_helper_funcs rockchip_crtc_helper_funcs = {
+       .dpms           = rockchip_drm_crtc_dpms,
+       .prepare        = rockchip_drm_crtc_prepare,
+       .commit         = rockchip_drm_crtc_commit,
+       .mode_fixup     = rockchip_drm_crtc_mode_fixup,
+       .mode_set       = rockchip_drm_crtc_mode_set,
+       .mode_set_base  = rockchip_drm_crtc_mode_set_base,
+       .load_lut       = rockchip_drm_crtc_load_lut,
+       .disable        = rockchip_drm_crtc_disable,
+};
+
+static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
+                                     struct drm_framebuffer *fb,
+                                     struct drm_pending_vblank_event *event)
+{
+       struct drm_device *dev = crtc->dev;
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+       struct drm_framebuffer *old_fb = crtc->fb;
+       int ret = -EINVAL;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* when the page flip is requested, crtc's dpms should be on */
+       if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
+               DRM_ERROR("failed page flip request.\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (event) {
+               /*
+                * the pipe from user always is 0 so we can set pipe number
+                * of current owner to event.
+                */
+               event->pipe = rockchip_crtc->pipe;
+
+               ret = drm_vblank_get(dev, rockchip_crtc->pipe);
+               if (ret) {
+                       DRM_DEBUG("failed to acquire vblank counter\n");
+
+                       goto out;
+               }
+
+               spin_lock_irq(&dev->event_lock);
+               list_add_tail(&event->base.link,
+                               &dev_priv->pageflip_event_list);
+               atomic_set(&rockchip_crtc->pending_flip, 1);
+               spin_unlock_irq(&dev->event_lock);
+
+               crtc->fb = fb;
+               ret = rockchip_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+                                                   NULL);
+               if (ret) {
+                       crtc->fb = old_fb;
+
+                       spin_lock_irq(&dev->event_lock);
+                       drm_vblank_put(dev, rockchip_crtc->pipe);
+                       list_del(&event->base.link);
+                       spin_unlock_irq(&dev->event_lock);
+
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+static void rockchip_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+       struct rockchip_drm_private *private = crtc->dev->dev_private;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       private->crtc[rockchip_crtc->pipe] = NULL;
+
+       drm_crtc_cleanup(crtc);
+       kfree(rockchip_crtc);
+}
+
+static int rockchip_drm_crtc_set_property(struct drm_crtc *crtc,
+                                       struct drm_property *property,
+                                       uint64_t val)
+{
+       struct drm_device *dev = crtc->dev;
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       if (property == dev_priv->crtc_mode_property) {
+               enum rockchip_crtc_mode mode = val;
+
+               if (mode == rockchip_crtc->mode)
+                       return 0;
+
+               rockchip_crtc->mode = mode;
+
+               switch (mode) {
+               case CRTC_MODE_NORMAL:
+                       rockchip_drm_crtc_commit(crtc);
+                       break;
+               case CRTC_MODE_BLANK:
+                       rockchip_plane_dpms(rockchip_crtc->plane,
+                                         DRM_MODE_DPMS_OFF);
+                       break;
+               default:
+                       break;
+               }
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct drm_crtc_funcs rockchip_crtc_funcs = {
+       .set_config     = drm_crtc_helper_set_config,
+       .page_flip      = rockchip_drm_crtc_page_flip,
+       .destroy        = rockchip_drm_crtc_destroy,
+       .set_property   = rockchip_drm_crtc_set_property,
+};
+
+static const struct drm_prop_enum_list mode_names[] = {
+       { CRTC_MODE_NORMAL, "normal" },
+       { CRTC_MODE_BLANK, "blank" },
+};
+
+static void rockchip_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       prop = dev_priv->crtc_mode_property;
+       if (!prop) {
+               prop = drm_property_create_enum(dev, 0, "mode", mode_names,
+                                               ARRAY_SIZE(mode_names));
+               if (!prop)
+                       return;
+
+               dev_priv->crtc_mode_property = prop;
+       }
+
+       drm_object_attach_property(&crtc->base, prop, 0);
+}
+
+int rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr)
+{
+       struct rockchip_drm_crtc *rockchip_crtc;
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct drm_crtc *crtc;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_crtc = kzalloc(sizeof(*rockchip_crtc), GFP_KERNEL);
+       if (!rockchip_crtc) {
+               DRM_ERROR("failed to allocate rockchip crtc\n");
+               return -ENOMEM;
+       }
+
+       rockchip_crtc->pipe = nr;
+       rockchip_crtc->dpms = DRM_MODE_DPMS_OFF;
+       init_waitqueue_head(&rockchip_crtc->pending_flip_queue);
+       atomic_set(&rockchip_crtc->pending_flip, 0);
+       rockchip_crtc->plane = rockchip_plane_init(dev, 1 << nr, true);
+       if (!rockchip_crtc->plane) {
+               kfree(rockchip_crtc);
+               return -ENOMEM;
+       }
+
+       crtc = &rockchip_crtc->drm_crtc;
+
+       private->crtc[nr] = crtc;
+
+       drm_crtc_init(dev, crtc, &rockchip_crtc_funcs);
+       drm_crtc_helper_add(crtc, &rockchip_crtc_helper_funcs);
+
+       rockchip_drm_crtc_attach_mode_property(crtc);
+
+       return 0;
+}
+
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct rockchip_drm_crtc *rockchip_crtc =
+               to_rockchip_crtc(private->crtc[crtc]);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
+               return -EPERM;
+
+       rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
+                       rockchip_drm_enable_vblank);
+
+       return 0;
+}
+
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct rockchip_drm_crtc *rockchip_crtc =
+               to_rockchip_crtc(private->crtc[crtc]);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
+               return;
+
+       rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
+                       rockchip_drm_disable_vblank);
+}
+
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+{
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+       struct drm_pending_vblank_event *e, *t;
+       struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+       struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(drm_crtc);
+       unsigned long flags;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
+                       base.link) {
+               /* if event's pipe isn't same as crtc then ignore it. */
+               if (crtc != e->pipe)
+                       continue;
+
+               list_del(&e->base.link);
+               drm_send_vblank_event(dev, -1, e);
+               drm_vblank_put(dev, crtc);
+               atomic_set(&rockchip_crtc->pending_flip, 0);
+               wake_up(&rockchip_crtc->pending_flip_queue);
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_crtc.h b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
new file mode 100644 (file)
index 0000000..077d839
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_CRTC_H_
+#define _ROCKCHIP_DRM_CRTC_H_
+
+int rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr);
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
new file mode 100644 (file)
index 0000000..da10ce5
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/rockchip_drm.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+
+#include <linux/dma-buf.h>
+
+struct rockchip_drm_dmabuf_attachment {
+       struct sg_table sgt;
+       enum dma_data_direction dir;
+       bool is_mapped;
+};
+
+static int rockchip_gem_attach_dma_buf(struct dma_buf *dmabuf,
+                                       struct device *dev,
+                                       struct dma_buf_attachment *attach)
+{
+       struct rockchip_drm_dmabuf_attachment *rockchip_attach;
+
+       rockchip_attach = kzalloc(sizeof(*rockchip_attach), GFP_KERNEL);
+       if (!rockchip_attach)
+               return -ENOMEM;
+
+       rockchip_attach->dir = DMA_NONE;
+       attach->priv = rockchip_attach;
+
+       return 0;
+}
+
+static void rockchip_gem_detach_dma_buf(struct dma_buf *dmabuf,
+                                       struct dma_buf_attachment *attach)
+{
+       struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
+       struct sg_table *sgt;
+
+       if (!rockchip_attach)
+               return;
+
+       sgt = &rockchip_attach->sgt;
+
+       if (rockchip_attach->dir != DMA_NONE)
+               dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
+                               rockchip_attach->dir);
+
+       sg_free_table(sgt);
+       kfree(rockchip_attach);
+       attach->priv = NULL;
+}
+
+static struct sg_table *
+               rockchip_gem_map_dma_buf(struct dma_buf_attachment *attach,
+                                       enum dma_data_direction dir)
+{
+       struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
+       struct rockchip_drm_gem_obj *gem_obj = attach->dmabuf->priv;
+       struct drm_device *dev = gem_obj->base.dev;
+       struct rockchip_drm_gem_buf *buf;
+       struct scatterlist *rd, *wr;
+       struct sg_table *sgt = NULL;
+       unsigned int i;
+       int nents, ret;
+
+       DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+       /* just return current sgt if already requested. */
+       if (rockchip_attach->dir == dir && rockchip_attach->is_mapped)
+               return &rockchip_attach->sgt;
+
+       buf = gem_obj->buffer;
+       if (!buf) {
+               DRM_ERROR("buffer is null.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       sgt = &rockchip_attach->sgt;
+
+       ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
+       if (ret) {
+               DRM_ERROR("failed to alloc sgt.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       rd = buf->sgt->sgl;
+       wr = sgt->sgl;
+       for (i = 0; i < sgt->orig_nents; ++i) {
+               sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
+               rd = sg_next(rd);
+               wr = sg_next(wr);
+       }
+
+       if (dir != DMA_NONE) {
+               nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
+               if (!nents) {
+                       DRM_ERROR("failed to map sgl with iommu.\n");
+                       sg_free_table(sgt);
+                       sgt = ERR_PTR(-EIO);
+                       goto err_unlock;
+               }
+       }
+
+       rockchip_attach->is_mapped = true;
+       rockchip_attach->dir = dir;
+       attach->priv = rockchip_attach;
+
+       DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
+
+err_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return sgt;
+}
+
+static void rockchip_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+                                               struct sg_table *sgt,
+                                               enum dma_data_direction dir)
+{
+       /* Nothing to do. */
+}
+
+static void rockchip_dmabuf_release(struct dma_buf *dmabuf)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = dmabuf->priv;
+
+       DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+       /*
+        * rockchip_dmabuf_release() call means that file object's
+        * f_count is 0 and it calls drm_gem_object_handle_unreference()
+        * to drop the references that these values had been increased
+        * at drm_prime_handle_to_fd()
+        */
+       if (rockchip_gem_obj->base.export_dma_buf == dmabuf) {
+               rockchip_gem_obj->base.export_dma_buf = NULL;
+
+               /*
+                * drop this gem object refcount to release allocated buffer
+                * and resources.
+                */
+               drm_gem_object_unreference_unlocked(&rockchip_gem_obj->base);
+       }
+}
+
+static void *rockchip_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+                                               unsigned long page_num)
+{
+       /* TODO */
+
+       return NULL;
+}
+
+static void rockchip_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+                                               unsigned long page_num,
+                                               void *addr)
+{
+       /* TODO */
+}
+
+static void *rockchip_gem_dmabuf_kmap(struct dma_buf *dma_buf,
+                                       unsigned long page_num)
+{
+       /* TODO */
+
+       return NULL;
+}
+
+static void rockchip_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
+                                       unsigned long page_num, void *addr)
+{
+       /* TODO */
+}
+
+static int rockchip_gem_dmabuf_mmap(struct dma_buf *dma_buf,
+       struct vm_area_struct *vma)
+{
+       return -ENOTTY;
+}
+
+static struct dma_buf_ops rockchip_dmabuf_ops = {
+       .attach                 = rockchip_gem_attach_dma_buf,
+       .detach                 = rockchip_gem_detach_dma_buf,
+       .map_dma_buf            = rockchip_gem_map_dma_buf,
+       .unmap_dma_buf          = rockchip_gem_unmap_dma_buf,
+       .kmap                   = rockchip_gem_dmabuf_kmap,
+       .kmap_atomic            = rockchip_gem_dmabuf_kmap_atomic,
+       .kunmap                 = rockchip_gem_dmabuf_kunmap,
+       .kunmap_atomic          = rockchip_gem_dmabuf_kunmap_atomic,
+       .mmap                   = rockchip_gem_dmabuf_mmap,
+       .release                = rockchip_dmabuf_release,
+};
+
+struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
+                               struct drm_gem_object *obj, int flags)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       return dma_buf_export(rockchip_gem_obj, &rockchip_dmabuf_ops,
+                               rockchip_gem_obj->base.size, flags);
+}
+
+struct drm_gem_object *rockchip_dmabuf_prime_import(struct drm_device *drm_dev,
+                               struct dma_buf *dma_buf)
+{
+       struct dma_buf_attachment *attach;
+       struct sg_table *sgt;
+       struct scatterlist *sgl;
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct rockchip_drm_gem_buf *buffer;
+       int ret;
+
+       DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+       /* is this one of own objects? */
+       if (dma_buf->ops == &rockchip_dmabuf_ops) {
+               struct drm_gem_object *obj;
+
+               rockchip_gem_obj = dma_buf->priv;
+               obj = &rockchip_gem_obj->base;
+
+               /* is it from our device? */
+               if (obj->dev == drm_dev) {
+                       /*
+                        * Importing dmabuf exported from out own gem increases
+                        * refcount on gem itself instead of f_count of dmabuf.
+                        */
+                       drm_gem_object_reference(obj);
+                       return obj;
+               }
+       }
+
+       attach = dma_buf_attach(dma_buf, drm_dev->dev);
+       if (IS_ERR(attach))
+               return ERR_PTR(-EINVAL);
+
+       get_dma_buf(dma_buf);
+
+       sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+       if (IS_ERR_OR_NULL(sgt)) {
+               ret = PTR_ERR(sgt);
+               goto err_buf_detach;
+       }
+
+       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+       if (!buffer) {
+               DRM_ERROR("failed to allocate rockchip_drm_gem_buf.\n");
+               ret = -ENOMEM;
+               goto err_unmap_attach;
+       }
+
+       rockchip_gem_obj = rockchip_drm_gem_init(drm_dev, dma_buf->size);
+       if (!rockchip_gem_obj) {
+               ret = -ENOMEM;
+               goto err_free_buffer;
+       }
+
+       sgl = sgt->sgl;
+
+       buffer->size = dma_buf->size;
+       buffer->dma_addr = sg_dma_address(sgl);
+
+       if (sgt->nents == 1) {
+               /* always physically continuous memory if sgt->nents is 1. */
+               rockchip_gem_obj->flags |= ROCKCHIP_BO_CONTIG;
+       } else {
+               /*
+                * this case could be CONTIG or NONCONTIG type but for now
+                * sets NONCONTIG.
+                * TODO. we have to find a way that exporter can notify
+                * the type of its own buffer to importer.
+                */
+               rockchip_gem_obj->flags |= ROCKCHIP_BO_NONCONTIG;
+       }
+
+       rockchip_gem_obj->buffer = buffer;
+       buffer->sgt = sgt;
+       rockchip_gem_obj->base.import_attach = attach;
+
+       DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr,
+                                                               buffer->size);
+
+       return &rockchip_gem_obj->base;
+
+err_free_buffer:
+       kfree(buffer);
+       buffer = NULL;
+err_unmap_attach:
+       dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+err_buf_detach:
+       dma_buf_detach(dma_buf, attach);
+       dma_buf_put(dma_buf);
+
+       return ERR_PTR(ret);
+}
+
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
new file mode 100644 (file)
index 0000000..f2e3750
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_DMABUF_H_
+#define _ROCKCHIP_DRM_DMABUF_H_
+
+#ifdef CONFIG_DRM_ROCKCHIP_DMABUF
+struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
+                               struct drm_gem_object *obj, int flags);
+
+struct drm_gem_object *rockchip_dmabuf_prime_import(struct drm_device *drm_dev,
+                                               struct dma_buf *dma_buf);
+#else
+#define rockchip_dmabuf_prime_export           NULL
+#define rockchip_dmabuf_prime_import           NULL
+#endif
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
new file mode 100644 (file)
index 0000000..581d99f
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_plane.h"
+#include "rockchip_drm_dmabuf.h"
+#include "rockchip_drm_iommu.h"
+
+#define DRIVER_NAME    "rockchip"
+#define DRIVER_DESC    "rockchip Soc DRM"
+#define DRIVER_DATE    "20140318"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+#define VBLANK_OFF_DELAY       50000
+
+/* platform device pointer for eynos drm device. */
+static struct platform_device *rockchip_drm_pdev;
+
+static int rockchip_drm_load(struct drm_device *dev, unsigned long flags)
+{
+       struct rockchip_drm_private *private;
+       int ret;
+       int nr;
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       private = kzalloc(sizeof(struct rockchip_drm_private), GFP_KERNEL);
+       if (!private) {
+               DRM_ERROR("failed to allocate private\n");
+               return -ENOMEM;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       INIT_LIST_HEAD(&private->pageflip_event_list);
+       dev->dev_private = (void *)private;
+
+       /*
+        * create mapping to manage iommu table and set a pointer to iommu
+        * mapping structure to iommu_mapping of private data.
+        * also this iommu_mapping can be used to check if iommu is supported
+        * or not.
+        */
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       ret = drm_create_iommu_mapping(dev);
+       if (ret < 0) {
+               DRM_ERROR("failed to create iommu mapping.\n");
+               goto err_crtc;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       drm_mode_config_init(dev);
+
+       /* init kms poll for handling hpd */
+       drm_kms_helper_poll_init(dev);
+
+       rockchip_drm_mode_config_init(dev);
+
+       /*
+        * ROCKCHIP4 is enough to have two CRTCs and each crtc would be used
+        * without dependency of hardware.
+        */
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       for (nr = 0; nr < MAX_CRTC; nr++) {
+               ret = rockchip_drm_crtc_create(dev, nr);
+               if (ret)
+                       goto err_release_iommu_mapping;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       for (nr = 0; nr < MAX_PLANE; nr++) {
+               struct drm_plane *plane;
+               unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+
+               plane = rockchip_plane_init(dev, possible_crtcs, false);
+               if (!plane)
+                       goto err_release_iommu_mapping;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       ret = drm_vblank_init(dev, MAX_CRTC);
+       if (ret)
+               goto err_release_iommu_mapping;
+
+       /*
+        * probe sub drivers such as display controller and hdmi driver,
+        * that were registered at probe() of platform driver
+        * to the sub driver and create encoder and connector for them.
+        */
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       ret = rockchip_drm_device_register(dev);
+       if (ret)
+               goto err_vblank;
+
+       /* setup possible_clones. */
+       rockchip_drm_encoder_setup(dev);
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       /*
+        * create and configure fb helper and also rockchip specific
+        * fbdev object.
+        */
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       ret = rockchip_drm_fbdev_init(dev);
+       if (ret) {
+               DRM_ERROR("failed to initialize drm fbdev\n");
+               goto err_drm_device;
+       }
+
+       drm_vblank_offdelay = VBLANK_OFF_DELAY;
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       return 0;
+
+err_drm_device:
+       rockchip_drm_device_unregister(dev);
+err_vblank:
+       drm_vblank_cleanup(dev);
+err_release_iommu_mapping:
+       drm_release_iommu_mapping(dev);
+err_crtc:
+       drm_mode_config_cleanup(dev);
+       kfree(private);
+
+       return ret;
+}
+
+static int rockchip_drm_unload(struct drm_device *dev)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       rockchip_drm_fbdev_fini(dev);
+       rockchip_drm_device_unregister(dev);
+       drm_vblank_cleanup(dev);
+       drm_kms_helper_poll_fini(dev);
+       drm_mode_config_cleanup(dev);
+
+       drm_release_iommu_mapping(dev);
+       kfree(dev->dev_private);
+
+       dev->dev_private = NULL;
+
+       return 0;
+}
+
+static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file)
+{
+       struct drm_rockchip_file_private *file_priv;
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+       if (!file_priv)
+               return -ENOMEM;
+
+       file->driver_priv = file_priv;
+
+       return rockchip_drm_subdrv_open(dev, file);
+}
+
+static void rockchip_drm_preclose(struct drm_device *dev,
+                                       struct drm_file *file)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct drm_pending_vblank_event *e, *t;
+       unsigned long flags;
+
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       /* release events of current file */
+       spin_lock_irqsave(&dev->event_lock, flags);
+       list_for_each_entry_safe(e, t, &private->pageflip_event_list,
+                       base.link) {
+               if (e->base.file_priv == file) {
+                       list_del(&e->base.link);
+                       e->base.destroy(&e->base);
+               }
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       rockchip_drm_subdrv_close(dev, file);
+}
+
+static void rockchip_drm_postclose(struct drm_device *dev, struct drm_file *file)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       if (!file->driver_priv)
+               return;
+
+       kfree(file->driver_priv);
+       file->driver_priv = NULL;
+}
+
+static void rockchip_drm_lastclose(struct drm_device *dev)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       rockchip_drm_fbdev_restore_mode(dev);
+}
+
+static const struct vm_operations_struct rockchip_drm_gem_vm_ops = {
+       .fault = rockchip_drm_gem_fault,
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+
+static struct drm_ioctl_desc rockchip_ioctls[] = {
+       DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_CREATE, rockchip_drm_gem_create_ioctl,
+                       DRM_UNLOCKED | DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MAP_OFFSET,
+                       rockchip_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
+                       DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MMAP,
+                       rockchip_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_GET,
+                       rockchip_drm_gem_get_ioctl, DRM_UNLOCKED),
+};
+
+static const struct file_operations rockchip_drm_driver_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .mmap           = rockchip_drm_gem_mmap,
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = drm_compat_ioctl,
+#endif
+       .release        = drm_release,
+};
+
+static struct drm_driver rockchip_drm_driver = {
+       .driver_features        = DRIVER_HAVE_IRQ | DRIVER_MODESET |
+                                       DRIVER_GEM | DRIVER_PRIME,
+       .load                   = rockchip_drm_load,
+       .unload                 = rockchip_drm_unload,
+       .open                   = rockchip_drm_open,
+       .preclose               = rockchip_drm_preclose,
+       .lastclose              = rockchip_drm_lastclose,
+       .postclose              = rockchip_drm_postclose,
+       .get_vblank_counter     = drm_vblank_count,
+       .enable_vblank          = rockchip_drm_crtc_enable_vblank,
+       .disable_vblank         = rockchip_drm_crtc_disable_vblank,
+       .gem_init_object        = rockchip_drm_gem_init_object,
+       .gem_free_object        = rockchip_drm_gem_free_object,
+       .gem_vm_ops             = &rockchip_drm_gem_vm_ops,
+       .dumb_create            = rockchip_drm_gem_dumb_create,
+       .dumb_map_offset        = rockchip_drm_gem_dumb_map_offset,
+       .dumb_destroy           = rockchip_drm_gem_dumb_destroy,
+       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+       .gem_prime_export       = rockchip_dmabuf_prime_export,
+       .gem_prime_import       = rockchip_dmabuf_prime_import,
+       .ioctls                 = rockchip_ioctls,
+       .fops                   = &rockchip_drm_driver_fops,
+       .name   = DRIVER_NAME,
+       .desc   = DRIVER_DESC,
+       .date   = DRIVER_DATE,
+       .major  = DRIVER_MAJOR,
+       .minor  = DRIVER_MINOR,
+};
+
+static int rockchip_drm_platform_probe(struct platform_device *pdev)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+
+       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+       rockchip_drm_driver.num_ioctls = DRM_ARRAY_SIZE(rockchip_ioctls);
+
+       return drm_platform_init(&rockchip_drm_driver, pdev);
+}
+
+static int rockchip_drm_platform_remove(struct platform_device *pdev)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+
+       drm_platform_exit(&rockchip_drm_driver, pdev);
+
+       return 0;
+}
+
+static struct platform_driver rockchip_drm_platform_driver = {
+       .probe          = rockchip_drm_platform_probe,
+       .remove         = rockchip_drm_platform_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "rockchip-drm",
+       },
+};
+
+static int __init rockchip_drm_init(void)
+{
+       int ret;
+
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+#ifdef CONFIG_DRM_RK3288_FIMD
+       ret = platform_driver_register(&fimd_driver);
+       if (ret < 0)
+               goto out_fimd;
+#endif
+#ifdef CONFIG_DRM_RK3188_FIMD
+       ret = platform_driver_register(&fimd_driver);
+       if (ret < 0)
+               goto out_fimd;
+#endif
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       ret = platform_driver_register(&rockchip_drm_platform_driver);
+       if (ret < 0)
+               goto out_drm;
+
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       rockchip_drm_pdev = platform_device_register_simple("rockchip-drm", -1,
+                               NULL, 0);
+       if (IS_ERR(rockchip_drm_pdev)) {
+               ret = PTR_ERR(rockchip_drm_pdev);
+               goto out;
+       }
+
+       printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
+       return 0;
+
+out:
+       platform_driver_unregister(&rockchip_drm_platform_driver);
+out_drm:
+#ifdef CONFIG_DRM_RK3188_FIMD
+       platform_driver_unregister(&fimd_driver);
+out_fimd:
+#endif
+#ifdef CONFIG_DRM_RK3288_FIMD
+       platform_driver_unregister(&fimd_driver);
+out_fimd:
+#endif
+       return ret;
+}
+
+static void __exit rockchip_drm_exit(void)
+{
+       DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+       platform_device_unregister(rockchip_drm_pdev);
+
+       platform_driver_unregister(&rockchip_drm_platform_driver);
+}
+
+module_init(rockchip_drm_init);
+module_exit(rockchip_drm_exit);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
new file mode 100644 (file)
index 0000000..2e60df5
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_DRV_H_
+#define _ROCKCHIP_DRM_DRV_H_
+
+#include <linux/module.h>
+
+#define MAX_CRTC       3
+#define MAX_PLANE      5
+#define MAX_FB_BUFFER  4
+#define DEFAULT_ZPOS   -1
+
+#define _wait_for(COND, MS) ({ \
+       unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
+       int ret__ = 0;                                                  \
+       while (!(COND)) {                                               \
+               if (time_after(jiffies, timeout__)) {                   \
+                       ret__ = -ETIMEDOUT;                             \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       ret__;                                                          \
+})
+
+#define wait_for(COND, MS) _wait_for(COND, MS)
+
+struct drm_device;
+struct rockchip_drm_overlay;
+struct drm_connector;
+
+extern unsigned int drm_vblank_offdelay;
+
+/* this enumerates display type. */
+enum rockchip_drm_output_type {
+       ROCKCHIP_DISPLAY_TYPE_NONE,
+       /* RGB or CPU Interface. */
+       ROCKCHIP_DISPLAY_TYPE_LCD,
+       /* HDMI Interface. */
+       ROCKCHIP_DISPLAY_TYPE_HDMI,
+       /* Virtual Display Interface. */
+       ROCKCHIP_DISPLAY_TYPE_VIDI,
+};
+
+/*
+ * Exynos drm overlay ops structure.
+ *
+ * @mode_set: copy drm overlay info to hw specific overlay info.
+ * @commit: apply hardware specific overlay data to registers.
+ * @enable: enable hardware specific overlay.
+ * @disable: disable hardware specific overlay.
+ */
+struct rockchip_drm_overlay_ops {
+       void (*mode_set)(struct device *subdrv_dev,
+                        struct rockchip_drm_overlay *overlay);
+       void (*commit)(struct device *subdrv_dev, int zpos);
+       void (*enable)(struct device *subdrv_dev, int zpos);
+       void (*disable)(struct device *subdrv_dev, int zpos);
+};
+
+/*
+ * Exynos drm common overlay structure.
+ *
+ * @fb_x: offset x on a framebuffer to be displayed.
+ *     - the unit is screen coordinates.
+ * @fb_y: offset y on a framebuffer to be displayed.
+ *     - the unit is screen coordinates.
+ * @fb_width: width of a framebuffer.
+ * @fb_height: height of a framebuffer.
+ * @src_width: width of a partial image to be displayed from framebuffer.
+ * @src_height: height of a partial image to be displayed from framebuffer.
+ * @crtc_x: offset x on hardware screen.
+ * @crtc_y: offset y on hardware screen.
+ * @crtc_width: window width to be displayed (hardware screen).
+ * @crtc_height: window height to be displayed (hardware screen).
+ * @mode_width: width of screen mode.
+ * @mode_height: height of screen mode.
+ * @refresh: refresh rate.
+ * @scan_flag: interlace or progressive way.
+ *     (it could be DRM_MODE_FLAG_*)
+ * @bpp: pixel size.(in bit)
+ * @pixel_format: fourcc pixel format of this overlay
+ * @dma_addr: array of bus(accessed by dma) address to the memory region
+ *           allocated for a overlay.
+ * @zpos: order of overlay layer(z position).
+ * @default_win: a window to be enabled.
+ * @color_key: color key on or off.
+ * @index_color: if using color key feature then this value would be used
+ *                     as index color.
+ * @local_path: in case of lcd type, local path mode on or off.
+ * @transparency: transparency on or off.
+ * @activated: activated or not.
+ *
+ * this structure is common to rockchip SoC and its contents would be copied
+ * to hardware specific overlay info.
+ */
+struct rockchip_drm_overlay {
+       unsigned int fb_x;
+       unsigned int fb_y;
+       unsigned int fb_width;
+       unsigned int fb_height;
+       unsigned int src_width;
+       unsigned int src_height;
+       unsigned int crtc_x;
+       unsigned int crtc_y;
+       unsigned int crtc_width;
+       unsigned int crtc_height;
+       unsigned int mode_width;
+       unsigned int mode_height;
+       unsigned int refresh;
+       unsigned int scan_flag;
+       unsigned int bpp;
+       unsigned int pitch;
+       uint32_t pixel_format;
+       dma_addr_t dma_addr[MAX_FB_BUFFER];
+       int zpos;
+
+       bool default_win;
+       bool color_key;
+       unsigned int index_color;
+       bool local_path;
+       bool transparency;
+       bool activated;
+};
+
+/*
+ * Exynos DRM Display Structure.
+ *     - this structure is common to analog tv, digital tv and lcd panel.
+ *
+ * @type: one of ROCKCHIP_DISPLAY_TYPE_LCD and HDMI.
+ * @is_connected: check for that display is connected or not.
+ * @get_edid: get edid modes from display driver.
+ * @get_panel: get panel object from display driver.
+ * @check_timing: check if timing is valid or not.
+ * @power_on: display device on or off.
+ */
+struct rockchip_drm_display_ops {
+       enum rockchip_drm_output_type type;
+       bool (*is_connected)(struct device *dev);
+       struct edid *(*get_edid)(struct device *dev,
+                       struct drm_connector *connector);
+       void *(*get_panel)(struct device *dev);
+       int (*check_timing)(struct device *dev, void *timing);
+       int (*power_on)(struct device *dev, int mode);
+};
+
+/*
+ * Exynos drm manager ops
+ *
+ * @dpms: control device power.
+ * @apply: set timing, vblank and overlay data to registers.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ *           would be called by encoder->mode_set().
+ * @get_max_resol: get maximum resolution to specific hardware.
+ * @commit: set current hw specific display mode to hw.
+ * @enable_vblank: specific driver callback for enabling vblank interrupt.
+ * @disable_vblank: specific driver callback for disabling vblank interrupt.
+ * @wait_for_vblank: wait for vblank interrupt to make sure that
+ *     hardware overlay is updated.
+ */
+struct rockchip_drm_manager_ops {
+       void (*dpms)(struct device *subdrv_dev, int mode);
+       void (*apply)(struct device *subdrv_dev);
+       void (*mode_fixup)(struct device *subdrv_dev,
+                               struct drm_connector *connector,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode);
+       void (*mode_set)(struct device *subdrv_dev, void *mode);
+       void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
+                               unsigned int *height);
+       void (*commit)(struct device *subdrv_dev);
+       int (*enable_vblank)(struct device *subdrv_dev);
+       void (*disable_vblank)(struct device *subdrv_dev);
+       void (*wait_for_vblank)(struct device *subdrv_dev);
+};
+
+/*
+ * Exynos drm common manager structure.
+ *
+ * @dev: pointer to device object for subdrv device driver.
+ *     sub drivers such as display controller or hdmi driver,
+ *     have their own device object.
+ * @ops: pointer to callbacks for rockchip drm specific framebuffer.
+ *     these callbacks should be set by specific drivers such fimd
+ *     or hdmi driver and are used to control hardware global registers.
+ * @overlay_ops: pointer to callbacks for rockchip drm specific framebuffer.
+ *     these callbacks should be set by specific drivers such fimd
+ *     or hdmi driver and are used to control hardware overlay reigsters.
+ * @display: pointer to callbacks for rockchip drm specific framebuffer.
+ *     these callbacks should be set by specific drivers such fimd
+ *     or hdmi driver and are used to control display devices such as
+ *     analog tv, digital tv and lcd panel and also get timing data for them.
+ */
+struct rockchip_drm_manager {
+       struct device *dev;
+       int pipe;
+       struct rockchip_drm_manager_ops *ops;
+       struct rockchip_drm_overlay_ops *overlay_ops;
+       struct rockchip_drm_display_ops *display_ops;
+};
+
+struct rockchip_drm_g2d_private {
+       struct device           *dev;
+       struct list_head        inuse_cmdlist;
+       struct list_head        event_list;
+       struct list_head        userptr_list;
+};
+
+struct rockchip_drm_ipp_private {
+       struct device   *dev;
+       struct list_head        event_list;
+};
+
+struct drm_rockchip_file_private {
+       struct rockchip_drm_g2d_private *g2d_priv;
+       struct rockchip_drm_ipp_private *ipp_priv;
+};
+
+/*
+ * Exynos drm private structure.
+ *
+ * @da_start: start address to device address space.
+ *     with iommu, device address space starts from this address
+ *     otherwise default one.
+ * @da_space_size: size of device address space.
+ *     if 0 then default value is used for it.
+ * @da_space_order: order to device address space.
+ */
+struct rockchip_drm_private {
+       struct drm_fb_helper *fb_helper;
+
+       /* list head for new event to be added. */
+       struct list_head pageflip_event_list;
+
+       /*
+        * created crtc object would be contained at this array and
+        * this array is used to be aware of which crtc did it request vblank.
+        */
+       struct drm_crtc *crtc[MAX_CRTC];
+       struct drm_property *plane_zpos_property;
+       struct drm_property *crtc_mode_property;
+
+       unsigned long da_start;
+       unsigned long da_space_size;
+       unsigned long da_space_order;
+};
+
+/*
+ * Exynos drm sub driver structure.
+ *
+ * @list: sub driver has its own list object to register to rockchip drm driver.
+ * @dev: pointer to device object for subdrv device driver.
+ * @drm_dev: pointer to drm_device and this pointer would be set
+ *     when sub driver calls rockchip_drm_subdrv_register().
+ * @manager: subdrv has its own manager to control a hardware appropriately
+ *     and we can access a hardware drawing on this manager.
+ * @probe: this callback would be called by rockchip drm driver after
+ *     subdrv is registered to it.
+ * @remove: this callback is used to release resources created
+ *     by probe callback.
+ * @open: this would be called with drm device file open.
+ * @close: this would be called with drm device file close.
+ * @encoder: encoder object owned by this sub driver.
+ * @connector: connector object owned by this sub driver.
+ */
+struct rockchip_drm_subdrv {
+       struct list_head list;
+       struct device *dev;
+       struct drm_device *drm_dev;
+       struct rockchip_drm_manager *manager;
+
+       int (*probe)(struct drm_device *drm_dev, struct device *dev);
+       void (*remove)(struct drm_device *drm_dev, struct device *dev);
+       int (*open)(struct drm_device *drm_dev, struct device *dev,
+                       struct drm_file *file);
+       void (*close)(struct drm_device *drm_dev, struct device *dev,
+                       struct drm_file *file);
+
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+};
+
+/*
+ * this function calls a probe callback registered to sub driver list and
+ * create its own encoder and connector and then set drm_device object
+ * to global one.
+ */
+int rockchip_drm_device_register(struct drm_device *dev);
+/*
+ * this function calls a remove callback registered to sub driver list and
+ * destroy its own encoder and connetor.
+ */
+int rockchip_drm_device_unregister(struct drm_device *dev);
+
+/*
+ * this function would be called by sub drivers such as display controller
+ * or hdmi driver to register this sub driver object to rockchip drm driver
+ * and when a sub driver is registered to rockchip drm driver a probe callback
+ * of the sub driver is called and creates its own encoder and connector.
+ */
+int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *drm_subdrv);
+
+/* this function removes subdrv list from rockchip drm driver */
+int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *drm_subdrv);
+
+int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
+void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
+
+/*
+ * this function registers rockchip drm hdmi platform device. It ensures only one
+ * instance of the device is created.
+ */
+int rockchip_platform_device_hdmi_register(void);
+
+/*
+ * this function unregisters rockchip drm hdmi platform device if it exists.
+ */
+void rockchip_platform_device_hdmi_unregister(void);
+
+/*
+ * this function registers rockchip drm ipp platform device.
+ */
+int rockchip_platform_device_ipp_register(void);
+
+/*
+ * this function unregisters rockchip drm ipp platform device if it exists.
+ */
+void rockchip_platform_device_ipp_unregister(void);
+
+extern struct platform_driver fimd_driver;
+extern struct platform_driver hdmi_driver;
+extern struct platform_driver mixer_driver;
+extern struct platform_driver rockchip_drm_common_hdmi_driver;
+extern struct platform_driver vidi_driver;
+extern struct platform_driver g2d_driver;
+extern struct platform_driver fimc_driver;
+extern struct platform_driver rotator_driver;
+extern struct platform_driver gsc_driver;
+extern struct platform_driver ipp_driver;
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_encoder.c b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
new file mode 100644 (file)
index 0000000..671267b
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_connector.h"
+
+#define to_rockchip_encoder(x) container_of(x, struct rockchip_drm_encoder,\
+                               drm_encoder)
+
+/*
+ * rockchip specific encoder structure.
+ *
+ * @drm_encoder: encoder object.
+ * @manager: specific encoder has its own manager to control a hardware
+ *     appropriately and we can access a hardware drawing on this manager.
+ * @dpms: store the encoder dpms value.
+ * @updated: indicate whether overlay data updating is needed or not.
+ */
+struct rockchip_drm_encoder {
+       struct drm_crtc                 *old_crtc;
+       struct drm_encoder              drm_encoder;
+       struct rockchip_drm_manager     *manager;
+       int                             dpms;
+       bool                            updated;
+};
+
+static void rockchip_drm_connector_power(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (rockchip_drm_best_encoder(connector) == encoder) {
+                       DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
+                                       connector->base.id, mode);
+
+                       rockchip_drm_display_power(connector, mode);
+               }
+       }
+}
+
+static void rockchip_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+       struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
+
+       DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
+
+       if (rockchip_encoder->dpms == mode) {
+               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+               return;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (manager_ops && manager_ops->apply)
+                       if (!rockchip_encoder->updated)
+                               manager_ops->apply(manager->dev);
+
+               rockchip_drm_connector_power(encoder, mode);
+               rockchip_encoder->dpms = mode;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               rockchip_drm_connector_power(encoder, mode);
+               rockchip_encoder->dpms = mode;
+               rockchip_encoder->updated = false;
+               break;
+       default:
+               DRM_ERROR("unspecified mode %d\n", mode);
+               break;
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+}
+
+static bool
+rockchip_drm_encoder_mode_fixup(struct drm_encoder *encoder,
+                              const struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+       struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder)
+                       if (manager_ops && manager_ops->mode_fixup)
+                               manager_ops->mode_fixup(manager->dev, connector,
+                                                       mode, adjusted_mode);
+       }
+
+       return true;
+}
+
+static void disable_plane_to_crtc(struct drm_device *dev,
+                                               struct drm_crtc *old_crtc,
+                                               struct drm_crtc *new_crtc)
+{
+       struct drm_plane *plane;
+
+       /*
+        * if old_crtc isn't same as encoder->crtc then it means that
+        * user changed crtc id to another one so the plane to old_crtc
+        * should be disabled and plane->crtc should be set to new_crtc
+        * (encoder->crtc)
+        */
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               if (plane->crtc == old_crtc) {
+                       /*
+                        * do not change below call order.
+                        *
+                        * plane->funcs->disable_plane call checks
+                        * if encoder->crtc is same as plane->crtc and if same
+                        * then overlay_ops->disable callback will be called
+                        * to diasble current hw overlay so plane->crtc should
+                        * have new_crtc because new_crtc was set to
+                        * encoder->crtc in advance.
+                        */
+                       plane->crtc = new_crtc;
+                       plane->funcs->disable_plane(plane);
+               }
+       }
+}
+
+static void rockchip_drm_encoder_mode_set(struct drm_encoder *encoder,
+                                        struct drm_display_mode *mode,
+                                        struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+       struct rockchip_drm_manager *manager;
+       struct rockchip_drm_manager_ops *manager_ops;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder) {
+                       struct rockchip_drm_encoder *rockchip_encoder;
+
+                       rockchip_encoder = to_rockchip_encoder(encoder);
+
+                       if (rockchip_encoder->old_crtc != encoder->crtc &&
+                                       rockchip_encoder->old_crtc) {
+
+                               /*
+                                * disable a plane to old crtc and change
+                                * crtc of the plane to new one.
+                                */
+                               disable_plane_to_crtc(dev,
+                                               rockchip_encoder->old_crtc,
+                                               encoder->crtc);
+                       }
+
+                       manager = rockchip_drm_get_manager(encoder);
+                       manager_ops = manager->ops;
+
+                       if (manager_ops && manager_ops->mode_set)
+                               manager_ops->mode_set(manager->dev,
+                                                       adjusted_mode);
+
+                       rockchip_encoder->old_crtc = encoder->crtc;
+               }
+       }
+}
+
+static void rockchip_drm_encoder_prepare(struct drm_encoder *encoder)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* drm framework doesn't check NULL. */
+}
+
+static void rockchip_drm_encoder_commit(struct drm_encoder *encoder)
+{
+       struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
+       struct rockchip_drm_manager *manager = rockchip_encoder->manager;
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (manager_ops && manager_ops->commit)
+               manager_ops->commit(manager->dev);
+
+       /*
+        * this will avoid one issue that overlay data is updated to
+        * real hardware two times.
+        * And this variable will be used to check if the data was
+        * already updated or not by rockchip_drm_encoder_dpms function.
+        */
+       rockchip_encoder->updated = true;
+
+       /*
+        * In case of setcrtc, there is no way to update encoder's dpms
+        * so update it here.
+        */
+       rockchip_encoder->dpms = DRM_MODE_DPMS_ON;
+}
+
+void rockchip_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
+{
+       struct rockchip_drm_encoder *rockchip_encoder;
+       struct rockchip_drm_manager_ops *ops;
+       struct drm_device *dev = fb->dev;
+       struct drm_encoder *encoder;
+
+       /*
+        * make sure that overlay data are updated to real hardware
+        * for all encoders.
+        */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               rockchip_encoder = to_rockchip_encoder(encoder);
+               ops = rockchip_encoder->manager->ops;
+
+               /*
+                * wait for vblank interrupt
+                * - this makes sure that overlay data are updated to
+                *      real hardware.
+                */
+               if (ops->wait_for_vblank)
+                       ops->wait_for_vblank(rockchip_encoder->manager->dev);
+       }
+}
+
+
+static void rockchip_drm_encoder_disable(struct drm_encoder *encoder)
+{
+       struct drm_plane *plane;
+       struct drm_device *dev = encoder->dev;
+
+       rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       /* all planes connected to this encoder should be also disabled. */
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               if (plane->crtc == encoder->crtc)
+                       plane->funcs->disable_plane(plane);
+       }
+}
+
+static struct drm_encoder_helper_funcs rockchip_encoder_helper_funcs = {
+       .dpms           = rockchip_drm_encoder_dpms,
+       .mode_fixup     = rockchip_drm_encoder_mode_fixup,
+       .mode_set       = rockchip_drm_encoder_mode_set,
+       .prepare        = rockchip_drm_encoder_prepare,
+       .commit         = rockchip_drm_encoder_commit,
+       .disable        = rockchip_drm_encoder_disable,
+};
+
+static void rockchip_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct rockchip_drm_encoder *rockchip_encoder =
+               to_rockchip_encoder(encoder);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_encoder->manager->pipe = -1;
+
+       drm_encoder_cleanup(encoder);
+       kfree(rockchip_encoder);
+}
+
+static struct drm_encoder_funcs rockchip_encoder_funcs = {
+       .destroy = rockchip_drm_encoder_destroy,
+};
+
+static unsigned int rockchip_drm_encoder_clones(struct drm_encoder *encoder)
+{
+       struct drm_encoder *clone;
+       struct drm_device *dev = encoder->dev;
+       struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
+       struct rockchip_drm_display_ops *display_ops =
+                               rockchip_encoder->manager->display_ops;
+       unsigned int clone_mask = 0;
+       int cnt = 0;
+
+       list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
+               switch (display_ops->type) {
+               case ROCKCHIP_DISPLAY_TYPE_LCD:
+               case ROCKCHIP_DISPLAY_TYPE_HDMI:
+               case ROCKCHIP_DISPLAY_TYPE_VIDI:
+                       clone_mask |= (1 << (cnt++));
+                       break;
+               default:
+                       continue;
+               }
+       }
+
+       return clone_mask;
+}
+
+void rockchip_drm_encoder_setup(struct drm_device *dev)
+{
+       struct drm_encoder *encoder;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               encoder->possible_clones = rockchip_drm_encoder_clones(encoder);
+}
+
+struct drm_encoder *
+rockchip_drm_encoder_create(struct drm_device *dev,
+                          struct rockchip_drm_manager *manager,
+                          unsigned int possible_crtcs)
+{
+       struct drm_encoder *encoder;
+       struct rockchip_drm_encoder *rockchip_encoder;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!manager || !possible_crtcs)
+               return NULL;
+
+       if (!manager->dev)
+               return NULL;
+
+       rockchip_encoder = kzalloc(sizeof(*rockchip_encoder), GFP_KERNEL);
+       if (!rockchip_encoder) {
+               DRM_ERROR("failed to allocate encoder\n");
+               return NULL;
+       }
+
+       rockchip_encoder->dpms = DRM_MODE_DPMS_OFF;
+       rockchip_encoder->manager = manager;
+       encoder = &rockchip_encoder->drm_encoder;
+       encoder->possible_crtcs = possible_crtcs;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(dev, encoder, &rockchip_encoder_funcs,
+                       DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &rockchip_encoder_helper_funcs);
+
+       DRM_DEBUG_KMS("encoder has been created\n");
+
+       return encoder;
+}
+
+struct rockchip_drm_manager *rockchip_drm_get_manager(struct drm_encoder *encoder)
+{
+       return to_rockchip_encoder(encoder)->manager;
+}
+
+void rockchip_drm_fn_encoder(struct drm_crtc *crtc, void *data,
+                           void (*fn)(struct drm_encoder *, void *))
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_encoder *encoder;
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct rockchip_drm_manager *manager;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               /*
+                * if crtc is detached from encoder, check pipe,
+                * otherwise check crtc attached to encoder
+                */
+               if (!encoder->crtc) {
+                       manager = to_rockchip_encoder(encoder)->manager;
+                       if (manager->pipe < 0 ||
+                                       private->crtc[manager->pipe] != crtc)
+                               continue;
+               } else {
+                       if (encoder->crtc != crtc)
+                               continue;
+               }
+
+               fn(encoder, data);
+       }
+}
+
+void rockchip_drm_enable_vblank(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+       int crtc = *(int *)data;
+
+       if (manager->pipe != crtc)
+               return;
+
+       if (manager_ops->enable_vblank)
+               manager_ops->enable_vblank(manager->dev);
+}
+
+void rockchip_drm_disable_vblank(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+       int crtc = *(int *)data;
+
+       if (manager->pipe != crtc)
+               return;
+
+       if (manager_ops->disable_vblank)
+               manager_ops->disable_vblank(manager->dev);
+}
+
+void rockchip_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
+       struct rockchip_drm_manager *manager = rockchip_encoder->manager;
+       struct rockchip_drm_manager_ops *manager_ops = manager->ops;
+       int mode = *(int *)data;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (manager_ops && manager_ops->dpms)
+               manager_ops->dpms(manager->dev, mode);
+
+       /*
+        * if this condition is ok then it means that the crtc is already
+        * detached from encoder and last function for detaching is properly
+        * done, so clear pipe from manager to prevent repeated call.
+        */
+       if (mode > DRM_MODE_DPMS_ON) {
+               if (!encoder->crtc)
+                       manager->pipe = -1;
+       }
+}
+
+void rockchip_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       int pipe = *(int *)data;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * when crtc is detached from encoder, this pipe is used
+        * to select manager operation
+        */
+       manager->pipe = pipe;
+}
+
+void rockchip_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct rockchip_drm_overlay *overlay = data;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (overlay_ops && overlay_ops->mode_set)
+               overlay_ops->mode_set(manager->dev, overlay);
+}
+
+void rockchip_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       int zpos = DEFAULT_ZPOS;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (data)
+               zpos = *(int *)data;
+
+       if (overlay_ops && overlay_ops->commit)
+               overlay_ops->commit(manager->dev, zpos);
+}
+
+void rockchip_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       int zpos = DEFAULT_ZPOS;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (data)
+               zpos = *(int *)data;
+
+       if (overlay_ops && overlay_ops->enable)
+               overlay_ops->enable(manager->dev, zpos);
+}
+
+void rockchip_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
+{
+       struct rockchip_drm_manager *manager =
+               to_rockchip_encoder(encoder)->manager;
+       struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       int zpos = DEFAULT_ZPOS;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (data)
+               zpos = *(int *)data;
+
+       if (overlay_ops && overlay_ops->disable)
+               overlay_ops->disable(manager->dev, zpos);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_encoder.h b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
new file mode 100644 (file)
index 0000000..8b89734
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_ENCODER_H_
+#define _ROCKCHIP_DRM_ENCODER_H_
+
+struct rockchip_drm_manager;
+
+void rockchip_drm_encoder_setup(struct drm_device *dev);
+struct drm_encoder *rockchip_drm_encoder_create(struct drm_device *dev,
+                                              struct rockchip_drm_manager *mgr,
+                                              unsigned int possible_crtcs);
+struct rockchip_drm_manager *
+rockchip_drm_get_manager(struct drm_encoder *encoder);
+void rockchip_drm_fn_encoder(struct drm_crtc *crtc, void *data,
+                           void (*fn)(struct drm_encoder *, void *));
+void rockchip_drm_enable_vblank(struct drm_encoder *encoder, void *data);
+void rockchip_drm_disable_vblank(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
+void rockchip_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
new file mode 100644 (file)
index 0000000..a2751ba
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <uapi/drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_iommu.h"
+#include "rockchip_drm_encoder.h"
+
+#define to_rockchip_fb(x)      container_of(x, struct rockchip_drm_fb, fb)
+
+/*
+ * rockchip specific framebuffer structure.
+ *
+ * @fb: drm framebuffer obejct.
+ * @buf_cnt: a buffer count to drm framebuffer.
+ * @rockchip_gem_obj: array of rockchip specific gem object containing a gem object.
+ */
+struct rockchip_drm_fb {
+       struct drm_framebuffer          fb;
+       unsigned int                    buf_cnt;
+       struct rockchip_drm_gem_obj     *rockchip_gem_obj[MAX_FB_BUFFER];
+};
+
+static int check_fb_gem_memory_type(struct drm_device *drm_dev,
+                               struct rockchip_drm_gem_obj *rockchip_gem_obj)
+{
+       unsigned int flags;
+
+       /*
+        * if rockchip drm driver supports iommu then framebuffer can use
+        * all the buffer types.
+        */
+       if (is_drm_iommu_supported(drm_dev))
+               return 0;
+
+       flags = rockchip_gem_obj->flags;
+
+       /*
+        * without iommu support, not support physically non-continuous memory
+        * for framebuffer.
+        */
+       if (IS_NONCONTIG_BUFFER(flags)) {
+               DRM_ERROR("cannot use this gem memory type for fb.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+       struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+       unsigned int i;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* make sure that overlay data are updated before relesing fb. */
+       rockchip_drm_encoder_complete_scanout(fb);
+
+       drm_framebuffer_cleanup(fb);
+
+       for (i = 0; i < ARRAY_SIZE(rockchip_fb->rockchip_gem_obj); i++) {
+               struct drm_gem_object *obj;
+
+               if (rockchip_fb->rockchip_gem_obj[i] == NULL)
+                       continue;
+
+               obj = &rockchip_fb->rockchip_gem_obj[i]->base;
+               drm_gem_object_unreference_unlocked(obj);
+       }
+
+       kfree(rockchip_fb);
+       rockchip_fb = NULL;
+}
+
+static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
+                                       struct drm_file *file_priv,
+                                       unsigned int *handle)
+{
+       struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* This fb should have only one gem object. */
+       if (WARN_ON(rockchip_fb->buf_cnt != 1))
+               return -EINVAL;
+
+       return drm_gem_handle_create(file_priv,
+                       &rockchip_fb->rockchip_gem_obj[0]->base, handle);
+}
+
+static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
+                               struct drm_file *file_priv, unsigned flags,
+                               unsigned color, struct drm_clip_rect *clips,
+                               unsigned num_clips)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* TODO */
+
+       return 0;
+}
+
+static struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
+       .destroy        = rockchip_drm_fb_destroy,
+       .create_handle  = rockchip_drm_fb_create_handle,
+       .dirty          = rockchip_drm_fb_dirty,
+};
+
+void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
+                                               unsigned int cnt)
+{
+       struct rockchip_drm_fb *rockchip_fb;
+
+       rockchip_fb = to_rockchip_fb(fb);
+
+       rockchip_fb->buf_cnt = cnt;
+}
+
+unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
+{
+       struct rockchip_drm_fb *rockchip_fb;
+
+       rockchip_fb = to_rockchip_fb(fb);
+
+       return rockchip_fb->buf_cnt;
+}
+
+struct drm_framebuffer *
+rockchip_drm_framebuffer_init(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *mode_cmd,
+                           struct drm_gem_object *obj)
+{
+       struct rockchip_drm_fb *rockchip_fb;
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       int ret;
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
+       if (ret < 0) {
+               DRM_ERROR("cannot use this gem memory type for fb.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
+       if (!rockchip_fb) {
+               DRM_ERROR("failed to allocate rockchip drm framebuffer\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
+       rockchip_fb->rockchip_gem_obj[0] = rockchip_gem_obj;
+
+       ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs);
+       if (ret) {
+               DRM_ERROR("failed to initialize framebuffer\n");
+               return ERR_PTR(ret);
+       }
+
+       return &rockchip_fb->fb;
+}
+
+static u32 rockchip_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       unsigned int cnt = 0;
+
+       if (mode_cmd->pixel_format != DRM_FORMAT_NV12)
+               return drm_format_num_planes(mode_cmd->pixel_format);
+
+       while (cnt != MAX_FB_BUFFER) {
+               if (!mode_cmd->handles[cnt])
+                       break;
+               cnt++;
+       }
+
+       /*
+        * check if NV12 or NV12M.
+        *
+        * NV12
+        * handles[0] = base1, offsets[0] = 0
+        * handles[1] = base1, offsets[1] = Y_size
+        *
+        * NV12M
+        * handles[0] = base1, offsets[0] = 0
+        * handles[1] = base2, offsets[1] = 0
+        */
+       if (cnt == 2) {
+               /*
+                * in case of NV12 format, offsets[1] is not 0 and
+                * handles[0] is same as handles[1].
+                */
+               if (mode_cmd->offsets[1] &&
+                       mode_cmd->handles[0] == mode_cmd->handles[1])
+                       cnt = 1;
+       }
+
+       return cnt;
+}
+
+static struct drm_framebuffer *
+rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+                     struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct drm_gem_object *obj;
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct rockchip_drm_fb *rockchip_fb;
+       int i, ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
+       if (!rockchip_fb) {
+               DRM_ERROR("failed to allocate rockchip drm framebuffer\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object\n");
+               ret = -ENOENT;
+               goto err_free;
+       }
+
+       drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
+       rockchip_fb->rockchip_gem_obj[0] = to_rockchip_gem_obj(obj);
+       rockchip_fb->buf_cnt = rockchip_drm_format_num_buffers(mode_cmd);
+
+       DRM_DEBUG_KMS("buf_cnt = %d\n", rockchip_fb->buf_cnt);
+
+       for (i = 1; i < rockchip_fb->buf_cnt; i++) {
+               obj = drm_gem_object_lookup(dev, file_priv,
+                               mode_cmd->handles[i]);
+               if (!obj) {
+                       DRM_ERROR("failed to lookup gem object\n");
+                       ret = -ENOENT;
+                       rockchip_fb->buf_cnt = i;
+                       goto err_unreference;
+               }
+
+               rockchip_gem_obj = to_rockchip_gem_obj(obj);
+               rockchip_fb->rockchip_gem_obj[i] = rockchip_gem_obj;
+
+               ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
+               if (ret < 0) {
+                       DRM_ERROR("cannot use this gem memory type for fb.\n");
+                       goto err_unreference;
+               }
+       }
+
+       ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs);
+       if (ret) {
+               DRM_ERROR("failed to init framebuffer.\n");
+               goto err_unreference;
+       }
+
+       return &rockchip_fb->fb;
+
+err_unreference:
+       for (i = 0; i < rockchip_fb->buf_cnt; i++) {
+               struct drm_gem_object *obj;
+
+               obj = &rockchip_fb->rockchip_gem_obj[i]->base;
+               if (obj)
+                       drm_gem_object_unreference_unlocked(obj);
+       }
+err_free:
+       kfree(rockchip_fb);
+       return ERR_PTR(ret);
+}
+
+struct rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
+                                               int index)
+{
+       struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+       struct rockchip_drm_gem_buf *buffer;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (index >= MAX_FB_BUFFER)
+               return NULL;
+
+       buffer = rockchip_fb->rockchip_gem_obj[index]->buffer;
+       if (!buffer)
+               return NULL;
+
+       DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
+
+       return buffer;
+}
+
+static void rockchip_drm_output_poll_changed(struct drm_device *dev)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct drm_fb_helper *fb_helper = private->fb_helper;
+
+       if (fb_helper)
+               drm_fb_helper_hotplug_event(fb_helper);
+}
+
+static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
+       .fb_create = rockchip_user_fb_create,
+       .output_poll_changed = rockchip_drm_output_poll_changed,
+};
+
+void rockchip_drm_mode_config_init(struct drm_device *dev)
+{
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+
+       /*
+        * set max width and height as default value(4096x4096).
+        * this value would be used to check framebuffer size limitation
+        * at drm_mode_addfb().
+        */
+       dev->mode_config.max_width = 4096;
+       dev->mode_config.max_height = 4096;
+
+       dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
new file mode 100644 (file)
index 0000000..757c529
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_FB_H_
+#define _ROCKCHIP_DRM_FB_H
+
+struct drm_framebuffer *
+rockchip_drm_framebuffer_init(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *mode_cmd,
+                           struct drm_gem_object *obj);
+
+/* get memory information of a drm framebuffer */
+struct rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
+                                                int index);
+
+void rockchip_drm_mode_config_init(struct drm_device *dev);
+
+/* set a buffer count to drm framebuffer. */
+void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
+                                               unsigned int cnt);
+
+/* get a buffer count to drm framebuffer. */
+unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
new file mode 100644 (file)
index 0000000..e1788ab
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_iommu.h"
+
+#define MAX_CONNECTOR          4
+#define PREFERRED_BPP          32
+
+#define to_rockchip_fbdev(x)   container_of(x, struct rockchip_drm_fbdev,\
+                               drm_fb_helper)
+
+struct rockchip_drm_fbdev {
+       struct drm_fb_helper            drm_fb_helper;
+       struct rockchip_drm_gem_obj     *rockchip_gem_obj;
+};
+
+static int rockchip_drm_fb_mmap(struct fb_info *info,
+                       struct vm_area_struct *vma)
+{
+       struct drm_fb_helper *helper = info->par;
+       struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(helper);
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = rockchip_fbd->rockchip_gem_obj;
+       struct rockchip_drm_gem_buf *buffer = rockchip_gem_obj->buffer;
+       unsigned long vm_size;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+
+       vm_size = vma->vm_end - vma->vm_start;
+
+       if (vm_size > buffer->size)
+               return -EINVAL;
+
+       ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages,
+               buffer->dma_addr, buffer->size, &buffer->dma_attrs);
+       if (ret < 0) {
+               DRM_ERROR("failed to mmap.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct fb_ops rockchip_drm_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_mmap        = rockchip_drm_fb_mmap,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_check_var   = drm_fb_helper_check_var,
+       .fb_set_par     = drm_fb_helper_set_par,
+       .fb_blank       = drm_fb_helper_blank,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_setcmap     = drm_fb_helper_setcmap,
+};
+
+static int rockchip_drm_fbdev_update(struct drm_fb_helper *helper,
+                                    struct drm_framebuffer *fb)
+{
+       struct fb_info *fbi = helper->fbdev;
+       struct drm_device *dev = helper->dev;
+       struct rockchip_drm_gem_buf *buffer;
+       unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+       unsigned long offset;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+
+       /* RGB formats use only one buffer */
+       buffer = rockchip_drm_fb_buffer(fb, 0);
+       if (!buffer) {
+               DRM_LOG_KMS("buffer is null.\n");
+               return -EFAULT;
+       }
+
+       /* map pages with kernel virtual space. */
+       if (!buffer->kvaddr) {
+               if (is_drm_iommu_supported(dev)) {
+                       unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
+
+                       buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
+                                       pgprot_writecombine(PAGE_KERNEL));
+               } else {
+                       phys_addr_t dma_addr = buffer->dma_addr;
+                       if (dma_addr)
+                               buffer->kvaddr = phys_to_virt(dma_addr);
+                       else
+                               buffer->kvaddr = (void __iomem *)NULL;
+               }
+               if (!buffer->kvaddr) {
+                       DRM_ERROR("failed to map pages to kernel space.\n");
+                       return -EIO;
+               }
+       }
+
+       /* buffer count to framebuffer always is 1 at booting time. */
+       rockchip_drm_fb_set_buf_cnt(fb, 1);
+
+       offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
+       offset += fbi->var.yoffset * fb->pitches[0];
+
+       dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
+       fbi->screen_base = buffer->kvaddr + offset;
+       if (is_drm_iommu_supported(dev))
+               fbi->fix.smem_start = (unsigned long)
+                       (page_to_phys(sg_page(buffer->sgt->sgl)) + offset);
+       else
+               fbi->fix.smem_start = (unsigned long)buffer->dma_addr;
+
+       fbi->screen_size = size;
+       fbi->fix.smem_len = size;
+
+       return 0;
+}
+
+static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
+                                   struct drm_fb_helper_surface_size *sizes)
+{
+       struct rockchip_drm_fbdev *rockchip_fbdev = to_rockchip_fbdev(helper);
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_device *dev = helper->dev;
+       struct fb_info *fbi;
+       struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+       struct platform_device *pdev = dev->platformdev;
+       unsigned long size;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
+                       sizes->surface_width, sizes->surface_height,
+                       sizes->surface_bpp);
+
+       mode_cmd.width = sizes->surface_width;
+       mode_cmd.height = sizes->surface_height;
+       mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+                                                         sizes->surface_depth);
+
+       mutex_lock(&dev->struct_mutex);
+
+       fbi = framebuffer_alloc(0, &pdev->dev);
+       if (!fbi) {
+               DRM_ERROR("failed to allocate fb info.\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       size = mode_cmd.pitches[0] * mode_cmd.height;
+
+       /* 0 means to allocate physically continuous memory */
+       rockchip_gem_obj = rockchip_drm_gem_create(dev, 0, size);
+       if (IS_ERR(rockchip_gem_obj)) {
+               ret = PTR_ERR(rockchip_gem_obj);
+               goto err_release_framebuffer;
+       }
+
+       rockchip_fbdev->rockchip_gem_obj = rockchip_gem_obj;
+
+       helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd,
+                       &rockchip_gem_obj->base);
+       if (IS_ERR(helper->fb)) {
+               DRM_ERROR("failed to create drm framebuffer.\n");
+               ret = PTR_ERR(helper->fb);
+               goto err_destroy_gem;
+       }
+
+       helper->fbdev = fbi;
+
+       fbi->par = helper;
+       fbi->flags = FBINFO_FLAG_DEFAULT;
+       fbi->fbops = &rockchip_drm_fb_ops;
+
+       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+       if (ret) {
+               DRM_ERROR("failed to allocate cmap.\n");
+               goto err_destroy_framebuffer;
+       }
+
+       ret = rockchip_drm_fbdev_update(helper, helper->fb);
+       if (ret < 0)
+               goto err_dealloc_cmap;
+
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+
+err_dealloc_cmap:
+       fb_dealloc_cmap(&fbi->cmap);
+err_destroy_framebuffer:
+       drm_framebuffer_cleanup(helper->fb);
+err_destroy_gem:
+       rockchip_drm_gem_destroy(rockchip_gem_obj);
+err_release_framebuffer:
+       framebuffer_release(fbi);
+
+/*
+ * if failed, all resources allocated above would be released by
+ * drm_mode_config_cleanup() when drm_load() had been called prior
+ * to any specific driver such as fimd or hdmi driver.
+ */
+out:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+static struct drm_fb_helper_funcs rockchip_drm_fb_helper_funcs = {
+       .fb_probe =     rockchip_drm_fbdev_create,
+};
+
+int rockchip_drm_fbdev_init(struct drm_device *dev)
+{
+       struct rockchip_drm_fbdev *fbdev;
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct drm_fb_helper *helper;
+       unsigned int num_crtc;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
+               return 0;
+
+       fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+       if (!fbdev) {
+               DRM_ERROR("failed to allocate drm fbdev.\n");
+               return -ENOMEM;
+       }
+
+       private->fb_helper = helper = &fbdev->drm_fb_helper;
+       helper->funcs = &rockchip_drm_fb_helper_funcs;
+
+       num_crtc = dev->mode_config.num_crtc;
+
+       ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR);
+       if (ret < 0) {
+               DRM_ERROR("failed to initialize drm fb helper.\n");
+               goto err_init;
+       }
+
+       ret = drm_fb_helper_single_add_all_connectors(helper);
+       if (ret < 0) {
+               DRM_ERROR("failed to register drm_fb_helper_connector.\n");
+               goto err_setup;
+
+       }
+
+       /* disable all the possible outputs/crtcs before entering KMS mode */
+       drm_helper_disable_unused_functions(dev);
+
+       ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
+       if (ret < 0) {
+               DRM_ERROR("failed to set up hw configuration.\n");
+               goto err_setup;
+       }
+
+       return 0;
+
+err_setup:
+       drm_fb_helper_fini(helper);
+
+err_init:
+       private->fb_helper = NULL;
+       kfree(fbdev);
+
+       return ret;
+}
+
+static void rockchip_drm_fbdev_destroy(struct drm_device *dev,
+                                     struct drm_fb_helper *fb_helper)
+{
+       struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(fb_helper);
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = rockchip_fbd->rockchip_gem_obj;
+       struct drm_framebuffer *fb;
+
+       if (is_drm_iommu_supported(dev) && rockchip_gem_obj->buffer->kvaddr)
+               vunmap(rockchip_gem_obj->buffer->kvaddr);
+
+       /* release drm framebuffer and real buffer */
+       if (fb_helper->fb && fb_helper->fb->funcs) {
+               fb = fb_helper->fb;
+               if (fb) {
+                       drm_framebuffer_unregister_private(fb);
+                       drm_framebuffer_remove(fb);
+               }
+       }
+
+       /* release linux framebuffer */
+       if (fb_helper->fbdev) {
+               struct fb_info *info;
+               int ret;
+
+               info = fb_helper->fbdev;
+               ret = unregister_framebuffer(info);
+               if (ret < 0)
+                       DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
+
+               if (info->cmap.len)
+                       fb_dealloc_cmap(&info->cmap);
+
+               framebuffer_release(info);
+       }
+
+       drm_fb_helper_fini(fb_helper);
+}
+
+void rockchip_drm_fbdev_fini(struct drm_device *dev)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+       struct rockchip_drm_fbdev *fbdev;
+
+       if (!private || !private->fb_helper)
+               return;
+
+       fbdev = to_rockchip_fbdev(private->fb_helper);
+
+       if (fbdev->rockchip_gem_obj)
+               rockchip_drm_gem_destroy(fbdev->rockchip_gem_obj);
+
+       rockchip_drm_fbdev_destroy(dev, private->fb_helper);
+       kfree(fbdev);
+       private->fb_helper = NULL;
+}
+
+void rockchip_drm_fbdev_restore_mode(struct drm_device *dev)
+{
+       struct rockchip_drm_private *private = dev->dev_private;
+
+       if (!private || !private->fb_helper)
+               return;
+
+       drm_modeset_lock_all(dev);
+       drm_fb_helper_restore_fbdev_mode(private->fb_helper);
+       drm_modeset_unlock_all(dev);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
new file mode 100644 (file)
index 0000000..cd8d746
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_FBDEV_H_
+#define _ROCKCHIP_DRM_FBDEV_H_
+
+int rockchip_drm_fbdev_init(struct drm_device *dev);
+int rockchip_drm_fbdev_reinit(struct drm_device *dev);
+void rockchip_drm_fbdev_fini(struct drm_device *dev);
+void rockchip_drm_fbdev_restore_mode(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
new file mode 100644 (file)
index 0000000..69700b9
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <drm/drmP.h>
+
+#include <linux/shmem_fs.h>
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_buf.h"
+
+static unsigned int convert_to_vm_err_msg(int msg)
+{
+       unsigned int out_msg;
+
+       switch (msg) {
+       case 0:
+       case -ERESTARTSYS:
+       case -EINTR:
+               out_msg = VM_FAULT_NOPAGE;
+               break;
+
+       case -ENOMEM:
+               out_msg = VM_FAULT_OOM;
+               break;
+
+       default:
+               out_msg = VM_FAULT_SIGBUS;
+               break;
+       }
+
+       return out_msg;
+}
+
+static int check_gem_flags(unsigned int flags)
+{
+       if (flags & ~(ROCKCHIP_BO_MASK)) {
+               DRM_ERROR("invalid flags.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void update_vm_cache_attr(struct rockchip_drm_gem_obj *obj,
+                                       struct vm_area_struct *vma)
+{
+       DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
+
+       /* non-cachable as default. */
+       if (obj->flags & ROCKCHIP_BO_CACHABLE)
+               vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       else if (obj->flags & ROCKCHIP_BO_WC)
+               vma->vm_page_prot =
+                       pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+       else
+               vma->vm_page_prot =
+                       pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+}
+
+static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
+{
+       /* TODO */
+
+       return roundup(size, PAGE_SIZE);
+}
+
+static int rockchip_drm_gem_map_buf(struct drm_gem_object *obj,
+                                       struct vm_area_struct *vma,
+                                       unsigned long f_vaddr,
+                                       pgoff_t page_offset)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
+       struct rockchip_drm_gem_buf *buf = rockchip_gem_obj->buffer;
+       struct scatterlist *sgl;
+       unsigned long pfn;
+       int i;
+
+       if (!buf->sgt)
+               return -EINTR;
+
+       if (page_offset >= (buf->size >> PAGE_SHIFT)) {
+               DRM_ERROR("invalid page offset\n");
+               return -EINVAL;
+       }
+
+       sgl = buf->sgt->sgl;
+       for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) {
+               if (page_offset < (sgl->length >> PAGE_SHIFT))
+                       break;
+               page_offset -=  (sgl->length >> PAGE_SHIFT);
+       }
+
+       pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset;
+
+       return vm_insert_mixed(vma, f_vaddr, pfn);
+}
+
+static int rockchip_drm_gem_handle_create(struct drm_gem_object *obj,
+                                       struct drm_file *file_priv,
+                                       unsigned int *handle)
+{
+       int ret;
+
+       /*
+        * allocate a id of idr table where the obj is registered
+        * and handle has the id what user can see.
+        */
+       ret = drm_gem_handle_create(file_priv, obj, handle);
+       if (ret)
+               return ret;
+
+       DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
+
+       /* drop reference from allocate - handle holds it now. */
+       drm_gem_object_unreference_unlocked(obj);
+
+       return 0;
+}
+
+void rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj)
+{
+       struct drm_gem_object *obj;
+       struct rockchip_drm_gem_buf *buf;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       obj = &rockchip_gem_obj->base;
+       buf = rockchip_gem_obj->buffer;
+
+       DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
+
+       /*
+        * do not release memory region from exporter.
+        *
+        * the region will be released by exporter
+        * once dmabuf's refcount becomes 0.
+        */
+       if (obj->import_attach)
+               goto out;
+
+       rockchip_drm_free_buf(obj->dev, rockchip_gem_obj->flags, buf);
+
+out:
+       rockchip_drm_fini_buf(obj->dev, buf);
+       rockchip_gem_obj->buffer = NULL;
+
+       if (obj->map_list.map)
+               drm_gem_free_mmap_offset(obj);
+
+       /* release file pointer to gem object. */
+       drm_gem_object_release(obj);
+
+       kfree(rockchip_gem_obj);
+       rockchip_gem_obj = NULL;
+}
+
+unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
+                                               unsigned int gem_handle,
+                                               struct drm_file *file_priv)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_gem_object *obj;
+
+       obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               return 0;
+       }
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       drm_gem_object_unreference_unlocked(obj);
+
+       return rockchip_gem_obj->buffer->size;
+}
+
+
+struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
+                                                     unsigned long size)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_gem_object *obj;
+       int ret;
+
+       rockchip_gem_obj = kzalloc(sizeof(*rockchip_gem_obj), GFP_KERNEL);
+       if (!rockchip_gem_obj) {
+               DRM_ERROR("failed to allocate rockchip gem object\n");
+               return NULL;
+       }
+
+       rockchip_gem_obj->size = size;
+       obj = &rockchip_gem_obj->base;
+
+       ret = drm_gem_object_init(dev, obj, size);
+       if (ret < 0) {
+               DRM_ERROR("failed to initialize gem object\n");
+               kfree(rockchip_gem_obj);
+               return NULL;
+       }
+
+       DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
+
+       return rockchip_gem_obj;
+}
+
+struct rockchip_drm_gem_obj *rockchip_drm_gem_create(struct drm_device *dev,
+                                               unsigned int flags,
+                                               unsigned long size)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct rockchip_drm_gem_buf *buf;
+       int ret;
+
+       if (!size) {
+               DRM_ERROR("invalid size.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       size = roundup_gem_size(size, flags);
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       ret = check_gem_flags(flags);
+       if (ret)
+               return ERR_PTR(ret);
+
+       buf = rockchip_drm_init_buf(dev, size);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+
+       rockchip_gem_obj = rockchip_drm_gem_init(dev, size);
+       if (!rockchip_gem_obj) {
+               ret = -ENOMEM;
+               goto err_fini_buf;
+       }
+
+       rockchip_gem_obj->buffer = buf;
+
+       /* set memory type and cache attribute from user side. */
+       rockchip_gem_obj->flags = flags;
+
+       ret = rockchip_drm_alloc_buf(dev, buf, flags);
+       if (ret < 0) {
+               drm_gem_object_release(&rockchip_gem_obj->base);
+               goto err_fini_buf;
+       }
+
+       return rockchip_gem_obj;
+
+err_fini_buf:
+       rockchip_drm_fini_buf(dev, buf);
+       return ERR_PTR(ret);
+}
+
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct drm_rockchip_gem_create *args = data;
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_gem_obj = rockchip_drm_gem_create(dev, args->flags, args->size);
+       if (IS_ERR(rockchip_gem_obj))
+               return PTR_ERR(rockchip_gem_obj);
+
+       ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base, file_priv,
+                       &args->handle);
+       if (ret) {
+               rockchip_drm_gem_destroy(rockchip_gem_obj);
+               return ret;
+       }
+
+       return 0;
+}
+
+dma_addr_t *rockchip_drm_gem_get_dma_addr(struct drm_device *dev,
+                                       unsigned int gem_handle,
+                                       struct drm_file *filp)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_gem_object *obj;
+
+       obj = drm_gem_object_lookup(dev, filp, gem_handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       return &rockchip_gem_obj->buffer->dma_addr;
+}
+
+void rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
+                                       unsigned int gem_handle,
+                                       struct drm_file *filp)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_gem_object *obj;
+
+       obj = drm_gem_object_lookup(dev, filp, gem_handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               return;
+       }
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       drm_gem_object_unreference_unlocked(obj);
+
+       /*
+        * decrease obj->refcount one more time because we has already
+        * increased it at rockchip_drm_gem_get_dma_addr().
+        */
+       drm_gem_object_unreference_unlocked(obj);
+}
+
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv)
+{
+       struct drm_rockchip_gem_map_off *args = data;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
+                       args->handle, (unsigned long)args->offset);
+
+       if (!(dev->driver->driver_features & DRIVER_GEM)) {
+               DRM_ERROR("does not support GEM.\n");
+               return -ENODEV;
+       }
+
+       return rockchip_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
+                       &args->offset);
+}
+
+static struct drm_file *rockchip_drm_find_drm_file(struct drm_device *drm_dev,
+                                                       struct file *filp)
+{
+       struct drm_file *file_priv;
+
+       /* find current process's drm_file from filelist. */
+       list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
+               if (file_priv->filp == filp)
+                       return file_priv;
+
+       WARN_ON(1);
+
+       return ERR_PTR(-EFAULT);
+}
+
+static int rockchip_drm_gem_mmap_buffer(struct file *filp,
+                                     struct vm_area_struct *vma)
+{
+       struct drm_gem_object *obj = filp->private_data;
+       struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
+       struct drm_device *drm_dev = obj->dev;
+       struct rockchip_drm_gem_buf *buffer;
+       struct drm_file *file_priv;
+       unsigned long vm_size;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_private_data = obj;
+       vma->vm_ops = drm_dev->driver->gem_vm_ops;
+
+       /* restore it to driver's fops. */
+       filp->f_op = fops_get(drm_dev->driver->fops);
+
+       file_priv = rockchip_drm_find_drm_file(drm_dev, filp);
+       if (IS_ERR(file_priv))
+               return PTR_ERR(file_priv);
+
+       /* restore it to drm_file. */
+       filp->private_data = file_priv;
+
+       update_vm_cache_attr(rockchip_gem_obj, vma);
+
+       vm_size = vma->vm_end - vma->vm_start;
+
+       /*
+        * a buffer contains information to physically continuous memory
+        * allocated by user request or at framebuffer creation.
+        */
+       buffer = rockchip_gem_obj->buffer;
+
+       /* check if user-requested size is valid. */
+       if (vm_size > buffer->size)
+               return -EINVAL;
+
+       ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
+                               buffer->dma_addr, buffer->size,
+                               &buffer->dma_attrs);
+       if (ret < 0) {
+               DRM_ERROR("failed to mmap.\n");
+               return ret;
+       }
+
+       /*
+        * take a reference to this mapping of the object. And this reference
+        * is unreferenced by the corresponding vm_close call.
+        */
+       drm_gem_object_reference(obj);
+
+       drm_vm_open_locked(drm_dev, vma);
+
+       return 0;
+}
+
+static const struct file_operations rockchip_drm_gem_fops = {
+       .mmap = rockchip_drm_gem_mmap_buffer,
+};
+
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_rockchip_gem_mmap *args = data;
+       struct drm_gem_object *obj;
+       unsigned int addr;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!(dev->driver->driver_features & DRIVER_GEM)) {
+               DRM_ERROR("does not support GEM.\n");
+               return -ENODEV;
+       }
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * We have to use gem object and its fops for specific mmaper,
+        * but vm_mmap() can deliver only filp. So we have to change
+        * filp->f_op and filp->private_data temporarily, then restore
+        * again. So it is important to keep lock until restoration the
+        * settings to prevent others from misuse of filp->f_op or
+        * filp->private_data.
+        */
+       mutex_lock(&dev->struct_mutex);
+
+       /*
+        * Set specific mmper's fops. And it will be restored by
+        * rockchip_drm_gem_mmap_buffer to dev->driver->fops.
+        * This is used to call specific mapper temporarily.
+        */
+       file_priv->filp->f_op = &rockchip_drm_gem_fops;
+
+       /*
+        * Set gem object to private_data so that specific mmaper
+        * can get the gem object. And it will be restored by
+        * rockchip_drm_gem_mmap_buffer to drm_file.
+        */
+       file_priv->filp->private_data = obj;
+
+       addr = vm_mmap(file_priv->filp, 0, args->size,
+                       PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+
+       drm_gem_object_unreference(obj);
+
+       if (IS_ERR((void *)addr)) {
+               /* check filp->f_op, filp->private_data are restored */
+               if (file_priv->filp->f_op == &rockchip_drm_gem_fops) {
+                       file_priv->filp->f_op = fops_get(dev->driver->fops);
+                       file_priv->filp->private_data = file_priv;
+               }
+               mutex_unlock(&dev->struct_mutex);
+               return PTR_ERR((void *)addr);
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       args->mapped = addr;
+
+       DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
+
+       return 0;
+}
+
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+                                     struct drm_file *file_priv)
+{      struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_rockchip_gem_info *args = data;
+       struct drm_gem_object *obj;
+
+       mutex_lock(&dev->struct_mutex);
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
+       }
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       args->flags = rockchip_gem_obj->flags;
+       args->size = rockchip_gem_obj->size;
+
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+struct vm_area_struct *rockchip_gem_get_vma(struct vm_area_struct *vma)
+{
+       struct vm_area_struct *vma_copy;
+
+       vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
+       if (!vma_copy)
+               return NULL;
+
+       if (vma->vm_ops && vma->vm_ops->open)
+               vma->vm_ops->open(vma);
+
+       if (vma->vm_file)
+               get_file(vma->vm_file);
+
+       memcpy(vma_copy, vma, sizeof(*vma));
+
+       vma_copy->vm_mm = NULL;
+       vma_copy->vm_next = NULL;
+       vma_copy->vm_prev = NULL;
+
+       return vma_copy;
+}
+
+void rockchip_gem_put_vma(struct vm_area_struct *vma)
+{
+       if (!vma)
+               return;
+
+       if (vma->vm_ops && vma->vm_ops->close)
+               vma->vm_ops->close(vma);
+
+       if (vma->vm_file)
+               fput(vma->vm_file);
+
+       kfree(vma);
+}
+
+int rockchip_gem_get_pages_from_userptr(unsigned long start,
+                                               unsigned int npages,
+                                               struct page **pages,
+                                               struct vm_area_struct *vma)
+{
+       int get_npages;
+
+       /* the memory region mmaped with VM_PFNMAP. */
+       if (vma_is_io(vma)) {
+               unsigned int i;
+
+               for (i = 0; i < npages; ++i, start += PAGE_SIZE) {
+                       unsigned long pfn;
+                       int ret = follow_pfn(vma, start, &pfn);
+                       if (ret)
+                               return ret;
+
+                       pages[i] = pfn_to_page(pfn);
+               }
+
+               if (i != npages) {
+                       DRM_ERROR("failed to get user_pages.\n");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+
+       get_npages = get_user_pages(current, current->mm, start,
+                                       npages, 1, 1, pages, NULL);
+       get_npages = max(get_npages, 0);
+       if (get_npages != npages) {
+               DRM_ERROR("failed to get user_pages.\n");
+               while (get_npages)
+                       put_page(pages[--get_npages]);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+void rockchip_gem_put_pages_to_userptr(struct page **pages,
+                                       unsigned int npages,
+                                       struct vm_area_struct *vma)
+{
+       if (!vma_is_io(vma)) {
+               unsigned int i;
+
+               for (i = 0; i < npages; i++) {
+                       set_page_dirty_lock(pages[i]);
+
+                       /*
+                        * undo the reference we took when populating
+                        * the table.
+                        */
+                       put_page(pages[i]);
+               }
+       }
+}
+
+int rockchip_gem_map_sgt_with_dma(struct drm_device *drm_dev,
+                               struct sg_table *sgt,
+                               enum dma_data_direction dir)
+{
+       int nents;
+
+       mutex_lock(&drm_dev->struct_mutex);
+
+       nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
+       if (!nents) {
+               DRM_ERROR("failed to map sgl with dma.\n");
+               mutex_unlock(&drm_dev->struct_mutex);
+               return nents;
+       }
+
+       mutex_unlock(&drm_dev->struct_mutex);
+       return 0;
+}
+
+void rockchip_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
+                               struct sg_table *sgt,
+                               enum dma_data_direction dir)
+{
+       dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
+}
+
+int rockchip_drm_gem_init_object(struct drm_gem_object *obj)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       return 0;
+}
+
+void rockchip_drm_gem_free_object(struct drm_gem_object *obj)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct rockchip_drm_gem_buf *buf;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+       buf = rockchip_gem_obj->buffer;
+
+       if (obj->import_attach)
+               drm_prime_gem_destroy(obj, buf->sgt);
+
+       rockchip_drm_gem_destroy(to_rockchip_gem_obj(obj));
+}
+
+int rockchip_drm_gem_dumb_create(struct drm_file *file_priv,
+                              struct drm_device *dev,
+                              struct drm_mode_create_dumb *args)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * alocate memory to be used for framebuffer.
+        * - this callback would be called by user application
+        *      with DRM_IOCTL_MODE_CREATE_DUMB command.
+        */
+
+       args->pitch = args->width * ((args->bpp + 7) / 8);
+       args->size = args->pitch * args->height;
+
+       rockchip_gem_obj = rockchip_drm_gem_create(dev, ROCKCHIP_BO_CONTIG |
+                                               ROCKCHIP_BO_WC, args->size);
+       if (IS_ERR(rockchip_gem_obj))
+               return PTR_ERR(rockchip_gem_obj);
+
+       ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base, file_priv,
+                       &args->handle);
+       if (ret) {
+               rockchip_drm_gem_destroy(rockchip_gem_obj);
+               return ret;
+       }
+
+       return 0;
+}
+
+int rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+                                  struct drm_device *dev, uint32_t handle,
+                                  uint64_t *offset)
+{
+       struct drm_gem_object *obj;
+       int ret = 0;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       mutex_lock(&dev->struct_mutex);
+
+       /*
+        * get offset of memory allocated for drm framebuffer.
+        * - this callback would be called by user application
+        *      with DRM_IOCTL_MODE_MAP_DUMB command.
+        */
+
+       obj = drm_gem_object_lookup(dev, file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       if (!obj->map_list.map) {
+               ret = drm_gem_create_mmap_offset(obj);
+               if (ret)
+                       goto out;
+       }
+
+       *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
+       DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
+
+out:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+int rockchip_drm_gem_dumb_destroy(struct drm_file *file_priv,
+                               struct drm_device *dev,
+                               unsigned int handle)
+{
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * obj->refcount and obj->handle_count are decreased and
+        * if both them are 0 then rockchip_drm_gem_free_object()
+        * would be called by callback to release resources.
+        */
+       ret = drm_gem_handle_delete(file_priv, handle);
+       if (ret < 0) {
+               DRM_ERROR("failed to delete drm_gem_handle.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int rockchip_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->dev;
+       unsigned long f_vaddr;
+       pgoff_t page_offset;
+       int ret;
+
+       page_offset = ((unsigned long)vmf->virtual_address -
+                       vma->vm_start) >> PAGE_SHIFT;
+       f_vaddr = (unsigned long)vmf->virtual_address;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = rockchip_drm_gem_map_buf(obj, vma, f_vaddr, page_offset);
+       if (ret < 0)
+               DRM_ERROR("failed to map a buffer with user.\n");
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return convert_to_vm_err_msg(ret);
+}
+
+int rockchip_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct rockchip_drm_gem_obj *rockchip_gem_obj;
+       struct drm_gem_object *obj;
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /* set vm_area_struct. */
+       ret = drm_gem_mmap(filp, vma);
+       if (ret < 0) {
+               DRM_ERROR("failed to mmap.\n");
+               return ret;
+       }
+
+       obj = vma->vm_private_data;
+       rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+       ret = check_gem_flags(rockchip_gem_obj->flags);
+       if (ret) {
+               drm_gem_vm_close(vma);
+               drm_gem_free_mmap_offset(obj);
+               return ret;
+       }
+
+       vma->vm_flags &= ~VM_PFNMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
+
+       update_vm_cache_attr(rockchip_gem_obj, vma);
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
new file mode 100644 (file)
index 0000000..098fef9
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_GEM_H_
+#define _ROCKCHIP_DRM_GEM_H_
+
+#define to_rockchip_gem_obj(x) container_of(x,\
+                       struct rockchip_drm_gem_obj, base)
+
+#define IS_NONCONTIG_BUFFER(f)         (f & ROCKCHIP_BO_NONCONTIG)
+
+/*
+ * rockchip drm gem buffer structure.
+ *
+ * @kvaddr: kernel virtual address to allocated memory region.
+ * *userptr: user space address.
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ *     - this address could be physical address without IOMMU and
+ *     device address with IOMMU.
+ * @write: whether pages will be written to by the caller.
+ * @pages: Array of backing pages.
+ * @sgt: sg table to transfer page data.
+ * @size: size of allocated memory region.
+ * @pfnmap: indicate whether memory region from userptr is mmaped with
+ *     VM_PFNMAP or not.
+ */
+struct rockchip_drm_gem_buf {
+       void __iomem            *kvaddr;
+       unsigned long           userptr;
+       dma_addr_t              dma_addr;
+       struct dma_attrs        dma_attrs;
+       unsigned int            write;
+       struct page             **pages;
+       struct sg_table         *sgt;
+       unsigned long           size;
+       bool                    pfnmap;
+};
+
+/*
+ * rockchip drm buffer structure.
+ *
+ * @base: a gem object.
+ *     - a new handle to this gem object would be created
+ *     by drm_gem_handle_create().
+ * @buffer: a pointer to rockchip_drm_gem_buffer object.
+ *     - contain the information to memory region allocated
+ *     by user request or at framebuffer creation.
+ *     continuous memory region allocated by user request
+ *     or at framebuffer creation.
+ * @size: size requested from user, in bytes and this size is aligned
+ *     in page unit.
+ * @vma: a pointer to vm_area.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
+ *
+ * P.S. this object would be transfered to user as kms_bo.handle so
+ *     user can access the buffer through kms_bo.handle.
+ */
+struct rockchip_drm_gem_obj {
+       struct drm_gem_object           base;
+       struct rockchip_drm_gem_buf     *buffer;
+       unsigned long                   size;
+       struct vm_area_struct           *vma;
+       unsigned int                    flags;
+};
+
+struct page **rockchip_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
+
+/* destroy a buffer with gem object */
+void rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj);
+
+/* create a private gem object and initialize it. */
+struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
+                                                     unsigned long size);
+
+/* create a new buffer with gem object */
+struct rockchip_drm_gem_obj *rockchip_drm_gem_create(struct drm_device *dev,
+                                               unsigned int flags,
+                                               unsigned long size);
+
+/*
+ * request gem object creation and buffer allocation as the size
+ * that it is calculated with framebuffer information such as width,
+ * height and bpp.
+ */
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+
+/*
+ * get dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be increased.
+ */
+dma_addr_t *rockchip_drm_gem_get_dma_addr(struct drm_device *dev,
+                                       unsigned int gem_handle,
+                                       struct drm_file *filp);
+
+/*
+ * put dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be decreased.
+ */
+void rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
+                                       unsigned int gem_handle,
+                                       struct drm_file *filp);
+
+/* get buffer offset to map to user space. */
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+
+/*
+ * mmap the physically continuous memory that a gem object contains
+ * to user space.
+ */
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+
+/* map user space allocated by malloc to pages. */
+int rockchip_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
+                                     struct drm_file *file_priv);
+
+/* get buffer information to memory region allocated by gem. */
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+                                     struct drm_file *file_priv);
+
+/* get buffer size to gem handle. */
+unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
+                                               unsigned int gem_handle,
+                                               struct drm_file *file_priv);
+
+/* initialize gem object. */
+int rockchip_drm_gem_init_object(struct drm_gem_object *obj);
+
+/* free gem object. */
+void rockchip_drm_gem_free_object(struct drm_gem_object *gem_obj);
+
+/* create memory region for drm framebuffer. */
+int rockchip_drm_gem_dumb_create(struct drm_file *file_priv,
+                              struct drm_device *dev,
+                              struct drm_mode_create_dumb *args);
+
+/* map memory region for drm framebuffer to user space. */
+int rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+                                  struct drm_device *dev, uint32_t handle,
+                                  uint64_t *offset);
+
+/*
+ * destroy memory region allocated.
+ *     - a gem handle and physical memory region pointed by a gem object
+ *     would be released by drm_gem_handle_delete().
+ */
+int rockchip_drm_gem_dumb_destroy(struct drm_file *file_priv,
+                               struct drm_device *dev,
+                               unsigned int handle);
+
+/* page fault handler and mmap fault address(virtual) to physical memory. */
+int rockchip_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+
+/* set vm_flags and we can change the vm attribute to other one at here. */
+int rockchip_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+static inline int vma_is_io(struct vm_area_struct *vma)
+{
+       return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
+}
+
+/* get a copy of a virtual memory region. */
+struct vm_area_struct *rockchip_gem_get_vma(struct vm_area_struct *vma);
+
+/* release a userspace virtual memory area. */
+void rockchip_gem_put_vma(struct vm_area_struct *vma);
+
+/* get pages from user space. */
+int rockchip_gem_get_pages_from_userptr(unsigned long start,
+                                               unsigned int npages,
+                                               struct page **pages,
+                                               struct vm_area_struct *vma);
+
+/* drop the reference to pages. */
+void rockchip_gem_put_pages_to_userptr(struct page **pages,
+                                       unsigned int npages,
+                                       struct vm_area_struct *vma);
+
+/* map sgt with dma region. */
+int rockchip_gem_map_sgt_with_dma(struct drm_device *drm_dev,
+                               struct sg_table *sgt,
+                               enum dma_data_direction dir);
+
+/* unmap sgt from dma region. */
+void rockchip_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
+                               struct sg_table *sgt,
+                               enum dma_data_direction dir);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_hdmi.c b/drivers/gpu/drm/rockchip/rockchip_drm_hdmi.c
new file mode 100644 (file)
index 0000000..2b44c30
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_hdmi.h"
+
+#define to_context(dev)                platform_get_drvdata(to_platform_device(dev))
+#define to_subdrv(dev)         to_context(dev)
+#define get_ctx_from_subdrv(subdrv)    container_of(subdrv,\
+                                       struct drm_hdmi_context, subdrv);
+
+/* platform device pointer for common drm hdmi device. */
+static struct platform_device *rockchip_drm_hdmi_pdev;
+
+/* Common hdmi subdrv needs to access the hdmi and mixer though context.
+* These should be initialied by the repective drivers */
+static struct rockchip_drm_hdmi_context *hdmi_ctx;
+static struct rockchip_drm_hdmi_context *mixer_ctx;
+
+/* these callback points shoud be set by specific drivers. */
+static struct rockchip_hdmi_ops *hdmi_ops;
+static struct rockchip_mixer_ops *mixer_ops;
+
+struct drm_hdmi_context {
+       struct rockchip_drm_subdrv      subdrv;
+       struct rockchip_drm_hdmi_context        *hdmi_ctx;
+       struct rockchip_drm_hdmi_context        *mixer_ctx;
+
+       bool    enabled[MIXER_WIN_NR];
+};
+
+int rockchip_platform_device_hdmi_register(void)
+{
+       struct platform_device *pdev;
+
+       if (rockchip_drm_hdmi_pdev)
+               return -EEXIST;
+
+       pdev = platform_device_register_simple(
+                       "rockchip-drm-hdmi", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       rockchip_drm_hdmi_pdev = pdev;
+
+       return 0;
+}
+
+void rockchip_platform_device_hdmi_unregister(void)
+{
+       if (rockchip_drm_hdmi_pdev) {
+               platform_device_unregister(rockchip_drm_hdmi_pdev);
+               rockchip_drm_hdmi_pdev = NULL;
+       }
+}
+
+void rockchip_hdmi_drv_attach(struct rockchip_drm_hdmi_context *ctx)
+{
+       if (ctx)
+               hdmi_ctx = ctx;
+}
+
+void rockchip_mixer_drv_attach(struct rockchip_drm_hdmi_context *ctx)
+{
+       if (ctx)
+               mixer_ctx = ctx;
+}
+
+void rockchip_hdmi_ops_register(struct rockchip_hdmi_ops *ops)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ops)
+               hdmi_ops = ops;
+}
+
+void rockchip_mixer_ops_register(struct rockchip_mixer_ops *ops)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ops)
+               mixer_ops = ops;
+}
+
+static bool drm_hdmi_is_connected(struct device *dev)
+{
+       struct drm_hdmi_context *ctx = to_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->is_connected)
+               return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
+
+       return false;
+}
+
+static struct edid *drm_hdmi_get_edid(struct device *dev,
+                       struct drm_connector *connector)
+{
+       struct drm_hdmi_context *ctx = to_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->get_edid)
+               return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
+
+       return NULL;
+}
+
+static int drm_hdmi_check_timing(struct device *dev, void *timing)
+{
+       struct drm_hdmi_context *ctx = to_context(dev);
+       int ret = 0;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+       * Both, mixer and hdmi should be able to handle the requested mode.
+       * If any of the two fails, return mode as BAD.
+       */
+
+       if (mixer_ops && mixer_ops->check_timing)
+               ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
+
+       if (ret)
+               return ret;
+
+       if (hdmi_ops && hdmi_ops->check_timing)
+               return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
+
+       return 0;
+}
+
+static int drm_hdmi_power_on(struct device *dev, int mode)
+{
+       struct drm_hdmi_context *ctx = to_context(dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->power_on)
+               return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
+
+       return 0;
+}
+
+static struct rockchip_drm_display_ops drm_hdmi_display_ops = {
+       .type = ROCKCHIP_DISPLAY_TYPE_HDMI,
+       .is_connected = drm_hdmi_is_connected,
+       .get_edid = drm_hdmi_get_edid,
+       .check_timing = drm_hdmi_check_timing,
+       .power_on = drm_hdmi_power_on,
+};
+
+static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+       struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
+       struct rockchip_drm_manager *manager = subdrv->manager;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->enable_vblank)
+               return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
+                                               manager->pipe);
+
+       return 0;
+}
+
+static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->disable_vblank)
+               return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
+}
+
+static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->wait_for_vblank)
+               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
+}
+
+static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
+                               struct drm_connector *connector,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_display_mode *m;
+       int mode_ok;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode);
+
+       /* just return if user desired mode exists. */
+       if (mode_ok == 0)
+               return;
+
+       /*
+        * otherwise, find the most suitable mode among modes and change it
+        * to adjusted_mode.
+        */
+       list_for_each_entry(m, &connector->modes, head) {
+               mode_ok = drm_hdmi_check_timing(subdrv_dev, m);
+
+               if (mode_ok == 0) {
+                       struct drm_mode_object base;
+                       struct list_head head;
+
+                       DRM_INFO("desired mode doesn't exist so\n");
+                       DRM_INFO("use the most suitable mode among modes.\n");
+
+                       DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
+                               m->hdisplay, m->vdisplay, m->vrefresh);
+
+                       /* preserve display mode header while copying. */
+                       head = adjusted_mode->head;
+                       base = adjusted_mode->base;
+                       memcpy(adjusted_mode, m, sizeof(*m));
+                       adjusted_mode->head = head;
+                       adjusted_mode->base = base;
+                       break;
+               }
+       }
+}
+
+static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->mode_set)
+               hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
+}
+
+static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
+                               unsigned int *width, unsigned int *height)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->get_max_resol)
+               hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
+}
+
+static void drm_hdmi_commit(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (hdmi_ops && hdmi_ops->commit)
+               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
+}
+
+static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->dpms)
+               mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
+
+       if (hdmi_ops && hdmi_ops->dpms)
+               hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
+}
+
+static void drm_hdmi_apply(struct device *subdrv_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+       int i;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       for (i = 0; i < MIXER_WIN_NR; i++) {
+               if (!ctx->enabled[i])
+                       continue;
+               if (mixer_ops && mixer_ops->win_commit)
+                       mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
+       }
+
+       if (hdmi_ops && hdmi_ops->commit)
+               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
+}
+
+static struct rockchip_drm_manager_ops drm_hdmi_manager_ops = {
+       .dpms = drm_hdmi_dpms,
+       .apply = drm_hdmi_apply,
+       .enable_vblank = drm_hdmi_enable_vblank,
+       .disable_vblank = drm_hdmi_disable_vblank,
+       .wait_for_vblank = drm_hdmi_wait_for_vblank,
+       .mode_fixup = drm_hdmi_mode_fixup,
+       .mode_set = drm_hdmi_mode_set,
+       .get_max_resol = drm_hdmi_get_max_resol,
+       .commit = drm_hdmi_commit,
+};
+
+static void drm_mixer_mode_set(struct device *subdrv_dev,
+               struct rockchip_drm_overlay *overlay)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (mixer_ops && mixer_ops->win_mode_set)
+               mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
+}
+
+static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (win < 0 || win > MIXER_WIN_NR) {
+               DRM_ERROR("mixer window[%d] is wrong\n", win);
+               return;
+       }
+
+       if (mixer_ops && mixer_ops->win_commit)
+               mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
+
+       ctx->enabled[win] = true;
+}
+
+static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (win < 0 || win > MIXER_WIN_NR) {
+               DRM_ERROR("mixer window[%d] is wrong\n", win);
+               return;
+       }
+
+       if (mixer_ops && mixer_ops->win_disable)
+               mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
+
+       ctx->enabled[win] = false;
+}
+
+static struct rockchip_drm_overlay_ops drm_hdmi_overlay_ops = {
+       .mode_set = drm_mixer_mode_set,
+       .commit = drm_mixer_commit,
+       .disable = drm_mixer_disable,
+};
+
+static struct rockchip_drm_manager hdmi_manager = {
+       .pipe           = -1,
+       .ops            = &drm_hdmi_manager_ops,
+       .overlay_ops    = &drm_hdmi_overlay_ops,
+       .display_ops    = &drm_hdmi_display_ops,
+};
+
+static int hdmi_subdrv_probe(struct drm_device *drm_dev,
+               struct device *dev)
+{
+       struct rockchip_drm_subdrv *subdrv = to_subdrv(dev);
+       struct drm_hdmi_context *ctx;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (!hdmi_ctx) {
+               DRM_ERROR("hdmi context not initialized.\n");
+               return -EFAULT;
+       }
+
+       if (!mixer_ctx) {
+               DRM_ERROR("mixer context not initialized.\n");
+               return -EFAULT;
+       }
+
+       ctx = get_ctx_from_subdrv(subdrv);
+
+       if (!ctx) {
+               DRM_ERROR("no drm hdmi context.\n");
+               return -EFAULT;
+       }
+
+       ctx->hdmi_ctx = hdmi_ctx;
+       ctx->mixer_ctx = mixer_ctx;
+
+       ctx->hdmi_ctx->drm_dev = drm_dev;
+       ctx->mixer_ctx->drm_dev = drm_dev;
+
+       if (mixer_ops->iommu_on)
+               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
+
+       return 0;
+}
+
+static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
+{
+       struct drm_hdmi_context *ctx;
+       struct rockchip_drm_subdrv *subdrv = to_subdrv(dev);
+
+       ctx = get_ctx_from_subdrv(subdrv);
+
+       if (mixer_ops->iommu_on)
+               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
+}
+
+static int rockchip_drm_hdmi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct rockchip_drm_subdrv *subdrv;
+       struct drm_hdmi_context *ctx;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               DRM_LOG_KMS("failed to alloc common hdmi context.\n");
+               return -ENOMEM;
+       }
+
+       subdrv = &ctx->subdrv;
+
+       subdrv->dev = dev;
+       subdrv->manager = &hdmi_manager;
+       subdrv->probe = hdmi_subdrv_probe;
+       subdrv->remove = hdmi_subdrv_remove;
+
+       platform_set_drvdata(pdev, subdrv);
+
+       rockchip_drm_subdrv_register(subdrv);
+
+       return 0;
+}
+
+static int rockchip_drm_hdmi_remove(struct platform_device *pdev)
+{
+       struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       rockchip_drm_subdrv_unregister(&ctx->subdrv);
+
+       return 0;
+}
+
+struct platform_driver rockchip_drm_common_hdmi_driver = {
+       .probe          = rockchip_drm_hdmi_probe,
+       .remove         = rockchip_drm_hdmi_remove,
+       .driver         = {
+               .name   = "rockchip-drm-hdmi",
+               .owner  = THIS_MODULE,
+       },
+};
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_hdmi.h b/drivers/gpu/drm/rockchip/rockchip_drm_hdmi.h
new file mode 100644 (file)
index 0000000..15c1f35
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_HDMI_H_
+#define _ROCKCHIP_DRM_HDMI_H_
+
+#define MIXER_WIN_NR           3
+#define MIXER_DEFAULT_WIN      0
+
+/*
+ * rockchip hdmi common context structure.
+ *
+ * @drm_dev: pointer to drm_device.
+ * @ctx: pointer to the context of specific device driver.
+ *     this context should be hdmi_context or mixer_context.
+ */
+struct rockchip_drm_hdmi_context {
+       struct drm_device       *drm_dev;
+       void                    *ctx;
+};
+
+struct rockchip_hdmi_ops {
+       /* display */
+       bool (*is_connected)(void *ctx);
+       struct edid *(*get_edid)(void *ctx,
+                       struct drm_connector *connector);
+       int (*check_timing)(void *ctx, struct fb_videomode *timing);
+       int (*power_on)(void *ctx, int mode);
+
+       /* manager */
+       void (*mode_set)(void *ctx, void *mode);
+       void (*get_max_resol)(void *ctx, unsigned int *width,
+                               unsigned int *height);
+       void (*commit)(void *ctx);
+       void (*dpms)(void *ctx, int mode);
+};
+
+struct rockchip_mixer_ops {
+       /* manager */
+       int (*iommu_on)(void *ctx, bool enable);
+       int (*enable_vblank)(void *ctx, int pipe);
+       void (*disable_vblank)(void *ctx);
+       void (*wait_for_vblank)(void *ctx);
+       void (*dpms)(void *ctx, int mode);
+
+       /* overlay */
+       void (*win_mode_set)(void *ctx, struct rockchip_drm_overlay *overlay);
+       void (*win_commit)(void *ctx, int zpos);
+       void (*win_disable)(void *ctx, int zpos);
+
+       /* display */
+       int (*check_timing)(void *ctx, struct fb_videomode *timing);
+};
+
+void rockchip_hdmi_drv_attach(struct rockchip_drm_hdmi_context *ctx);
+void rockchip_mixer_drv_attach(struct rockchip_drm_hdmi_context *ctx);
+void rockchip_hdmi_ops_register(struct rockchip_hdmi_ops *ops);
+void rockchip_mixer_ops_register(struct rockchip_mixer_ops *ops);
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_iommu.c b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
new file mode 100644 (file)
index 0000000..7582e2b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drmP.h>
+#include <drm/rockchip_drm.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/kref.h>
+
+#include <asm/dma-iommu.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_iommu.h"
+
+/*
+ * drm_create_iommu_mapping - create a mapping structure
+ *
+ * @drm_dev: DRM device
+ */
+int drm_create_iommu_mapping(struct drm_device *drm_dev)
+{
+       struct dma_iommu_mapping *mapping = NULL;
+       struct rockchip_drm_private *priv = drm_dev->dev_private;
+       struct device *dev = drm_dev->dev;
+
+       if (!priv->da_start)
+               priv->da_start = ROCKCHIP_DEV_ADDR_START;
+       if (!priv->da_space_size)
+               priv->da_space_size = ROCKCHIP_DEV_ADDR_SIZE;
+       if (!priv->da_space_order)
+               priv->da_space_order = ROCKCHIP_DEV_ADDR_ORDER;
+
+       mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
+                                               priv->da_space_size,
+                                               priv->da_space_order);
+       if (IS_ERR(mapping))
+               return PTR_ERR(mapping);
+
+       dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+                                       GFP_KERNEL);
+       dma_set_max_seg_size(dev, 0xffffffffu);
+       dev->archdata.mapping = mapping;
+
+       return 0;
+}
+
+/*
+ * drm_release_iommu_mapping - release iommu mapping structure
+ *
+ * @drm_dev: DRM device
+ *
+ * if mapping->kref becomes 0 then all things related to iommu mapping
+ * will be released
+ */
+void drm_release_iommu_mapping(struct drm_device *drm_dev)
+{
+       struct device *dev = drm_dev->dev;
+
+       arm_iommu_release_mapping(dev->archdata.mapping);
+}
+
+/*
+ * drm_iommu_attach_device- attach device to iommu mapping
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be attach
+ *
+ * This function should be called by sub drivers to attach it to iommu
+ * mapping.
+ */
+int drm_iommu_attach_device(struct drm_device *drm_dev,
+                               struct device *subdrv_dev)
+{
+       struct device *dev = drm_dev->dev;
+       int ret;
+
+       if (!dev->archdata.mapping) {
+               DRM_ERROR("iommu_mapping is null.\n");
+               return -EFAULT;
+       }
+
+       subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
+                                       sizeof(*subdrv_dev->dma_parms),
+                                       GFP_KERNEL);
+       dma_set_max_seg_size(subdrv_dev, 0xffffffffu);
+
+       ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("failed iommu attach.\n");
+               return ret;
+       }
+
+       /*
+        * Set dma_ops to drm_device just one time.
+        *
+        * The dma mapping api needs device object and the api is used
+        * to allocate physial memory and map it with iommu table.
+        * If iommu attach succeeded, the sub driver would have dma_ops
+        * for iommu and also all sub drivers have same dma_ops.
+        */
+       if (!dev->archdata.dma_ops)
+               dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops;
+
+       return 0;
+}
+
+/*
+ * drm_iommu_detach_device -detach device address space mapping from device
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be detached
+ *
+ * This function should be called by sub drivers to detach it from iommu
+ * mapping
+ */
+void drm_iommu_detach_device(struct drm_device *drm_dev,
+                               struct device *subdrv_dev)
+{
+       struct device *dev = drm_dev->dev;
+       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+       if (!mapping || !mapping->domain)
+               return;
+
+       iommu_detach_device(mapping->domain, subdrv_dev);
+       drm_release_iommu_mapping(drm_dev);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_iommu.h b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
new file mode 100644 (file)
index 0000000..473ad3e
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _ROCKCHIP_DRM_IOMMU_H_
+#define _ROCKCHIP_DRM_IOMMU_H_
+
+#define ROCKCHIP_DEV_ADDR_START        0x20000000
+#define ROCKCHIP_DEV_ADDR_SIZE 0x40000000
+#define ROCKCHIP_DEV_ADDR_ORDER        0x0
+
+#ifdef CONFIG_DRM_ROCKCHIP_IOMMU
+
+int drm_create_iommu_mapping(struct drm_device *drm_dev);
+
+void drm_release_iommu_mapping(struct drm_device *drm_dev);
+
+int drm_iommu_attach_device(struct drm_device *drm_dev,
+                               struct device *subdrv_dev);
+
+void drm_iommu_detach_device(struct drm_device *dev_dev,
+                               struct device *subdrv_dev);
+
+static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
+{
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+       struct device *dev = drm_dev->dev;
+
+       return dev->archdata.mapping ? true : false;
+#else
+       return false;
+#endif
+}
+
+#else
+
+struct dma_iommu_mapping;
+static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
+{
+       return 0;
+}
+
+static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
+{
+}
+
+static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
+                                               struct device *subdrv_dev)
+{
+       return 0;
+}
+
+static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
+                                               struct device *subdrv_dev)
+{
+}
+
+static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
+{
+       return false;
+}
+
+#endif
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_plane.c b/drivers/gpu/drm/rockchip/rockchip_drm_plane.c
new file mode 100644 (file)
index 0000000..956c7cc
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+
+#include <drm/rockchip_drm.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+
+#define to_rockchip_plane(x)   container_of(x, struct rockchip_plane, base)
+
+struct rockchip_plane {
+       struct drm_plane                base;
+       struct rockchip_drm_overlay     overlay;
+       bool                            enabled;
+};
+
+static const uint32_t formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV12MT,
+};
+
+/*
+ * This function is to get X or Y size shown via screen. This needs length and
+ * start position of CRTC.
+ *
+ *      <--- length --->
+ * CRTC ----------------
+ *      ^ start        ^ end
+ *
+ * There are six cases from a to f.
+ *
+ *             <----- SCREEN ----->
+ *             0                 last
+ *   ----------|------------------|----------
+ * CRTCs
+ * a -------
+ *        b -------
+ *        c --------------------------
+ *                 d --------
+ *                           e -------
+ *                                  f -------
+ */
+static int rockchip_plane_get_size(int start, unsigned length, unsigned last)
+{
+       int end = start + length;
+       int size = 0;
+
+       if (start <= 0) {
+               if (end > 0)
+                       size = min_t(unsigned, end, last);
+       } else if (start <= last) {
+               size = min_t(unsigned, last - start, length);
+       }
+
+       return size;
+}
+
+int rockchip_plane_mode_set(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 rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+       struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+       unsigned int actual_w;
+       unsigned int actual_h;
+       int nr;
+       int i;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       nr = rockchip_drm_fb_get_buf_cnt(fb);
+       for (i = 0; i < nr; i++) {
+               struct rockchip_drm_gem_buf *buffer = rockchip_drm_fb_buffer(fb, i);
+
+               if (!buffer) {
+                       DRM_LOG_KMS("buffer is null\n");
+                       return -EFAULT;
+               }
+
+               overlay->dma_addr[i] = buffer->dma_addr;
+
+               DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
+                               i, (unsigned long)overlay->dma_addr[i]);
+       }
+
+       actual_w = rockchip_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
+       actual_h = rockchip_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
+
+       if (crtc_x < 0) {
+               if (actual_w)
+                       src_x -= crtc_x;
+               crtc_x = 0;
+       }
+
+       if (crtc_y < 0) {
+               if (actual_h)
+                       src_y -= crtc_y;
+               crtc_y = 0;
+       }
+
+       /* set drm framebuffer data. */
+       overlay->fb_x = src_x;
+       overlay->fb_y = src_y;
+       overlay->fb_width = fb->width;
+       overlay->fb_height = fb->height;
+       overlay->src_width = src_w;
+       overlay->src_height = src_h;
+       overlay->bpp = fb->bits_per_pixel;
+       overlay->pitch = fb->pitches[0];
+       overlay->pixel_format = fb->pixel_format;
+
+       /* set overlay range to be displayed. */
+       overlay->crtc_x = crtc_x;
+       overlay->crtc_y = crtc_y;
+       overlay->crtc_width = actual_w;
+       overlay->crtc_height = actual_h;
+
+       /* set drm mode data. */
+       overlay->mode_width = crtc->mode.hdisplay;
+       overlay->mode_height = crtc->mode.vdisplay;
+       overlay->refresh = crtc->mode.vrefresh;
+       overlay->scan_flag = crtc->mode.flags;
+
+       DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
+                       overlay->crtc_x, overlay->crtc_y,
+                       overlay->crtc_width, overlay->crtc_height);
+
+       rockchip_drm_fn_encoder(crtc, overlay, rockchip_drm_encoder_plane_mode_set);
+
+       return 0;
+}
+
+void rockchip_plane_commit(struct drm_plane *plane)
+{
+       struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+       struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+
+       rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                       rockchip_drm_encoder_plane_commit);
+}
+
+void rockchip_plane_dpms(struct drm_plane *plane, int mode)
+{
+       struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+       struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       if (mode == DRM_MODE_DPMS_ON) {
+               if (rockchip_plane->enabled)
+                       return;
+
+               rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                               rockchip_drm_encoder_plane_enable);
+
+               rockchip_plane->enabled = true;
+       } else {
+               if (!rockchip_plane->enabled)
+                       return;
+
+               rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                               rockchip_drm_encoder_plane_disable);
+
+               rockchip_plane->enabled = false;
+       }
+}
+
+static int
+rockchip_update_plane(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)
+{
+       int ret;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       ret = rockchip_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
+                       crtc_w, crtc_h, src_x >> 16, src_y >> 16,
+                       src_w >> 16, src_h >> 16);
+       if (ret < 0)
+               return ret;
+
+       plane->crtc = crtc;
+
+       rockchip_plane_commit(plane);
+       rockchip_plane_dpms(plane, DRM_MODE_DPMS_ON);
+
+       return 0;
+}
+
+static int rockchip_disable_plane(struct drm_plane *plane)
+{
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       rockchip_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+
+       return 0;
+}
+
+static void rockchip_plane_destroy(struct drm_plane *plane)
+{
+       struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       rockchip_disable_plane(plane);
+       drm_plane_cleanup(plane);
+       kfree(rockchip_plane);
+}
+
+static int rockchip_plane_set_property(struct drm_plane *plane,
+                                    struct drm_property *property,
+                                    uint64_t val)
+{
+       struct drm_device *dev = plane->dev;
+       struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       if (property == dev_priv->plane_zpos_property) {
+               rockchip_plane->overlay.zpos = val;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct drm_plane_funcs rockchip_plane_funcs = {
+       .update_plane   = rockchip_update_plane,
+       .disable_plane  = rockchip_disable_plane,
+       .destroy        = rockchip_plane_destroy,
+       .set_property   = rockchip_plane_set_property,
+};
+
+static void rockchip_plane_attach_zpos_property(struct drm_plane *plane)
+{
+       struct drm_device *dev = plane->dev;
+       struct rockchip_drm_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       prop = dev_priv->plane_zpos_property;
+       if (!prop) {
+               prop = drm_property_create_range(dev, 0, "zpos", 0,
+                                                MAX_PLANE - 1);
+               if (!prop)
+                       return;
+
+               dev_priv->plane_zpos_property = prop;
+       }
+
+       drm_object_attach_property(&plane->base, prop, 0);
+}
+
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+                                   unsigned int possible_crtcs, bool priv)
+{
+       struct rockchip_plane *rockchip_plane;
+       int err;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       rockchip_plane = kzalloc(sizeof(struct rockchip_plane), GFP_KERNEL);
+       if (!rockchip_plane) {
+               DRM_ERROR("failed to allocate plane\n");
+               return NULL;
+       }
+
+       err = drm_plane_init(dev, &rockchip_plane->base, possible_crtcs,
+                             &rockchip_plane_funcs, formats, ARRAY_SIZE(formats),
+                             priv);
+       if (err) {
+               DRM_ERROR("failed to initialize plane\n");
+               kfree(rockchip_plane);
+               return NULL;
+       }
+
+       if (priv)
+               rockchip_plane->overlay.zpos = DEFAULT_ZPOS;
+       else
+               rockchip_plane_attach_zpos_property(&rockchip_plane->base);
+
+       return &rockchip_plane->base;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_plane.h b/drivers/gpu/drm/rockchip/rockchip_drm_plane.h
new file mode 100644 (file)
index 0000000..a806d7c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ROCKCHIP, Inc.
+ * Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+int rockchip_plane_mode_set(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);
+void rockchip_plane_commit(struct drm_plane *plane);
+void rockchip_plane_dpms(struct drm_plane *plane, int mode);
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+                                   unsigned int possible_crtcs, bool priv);
diff --git a/drivers/gpu/drm/rockchip/screen/.gitignore b/drivers/gpu/drm/rockchip/screen/.gitignore
new file mode 100644 (file)
index 0000000..262e546
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+*lcd.h
diff --git a/drivers/gpu/drm/rockchip/screen/Kconfig b/drivers/gpu/drm/rockchip/screen/Kconfig
new file mode 100755 (executable)
index 0000000..78d3405
--- /dev/null
@@ -0,0 +1,14 @@
+choice
+       prompt  "LCD Panel Select"
+
+config LCD_GENERAL
+       bool "General lcd panel"
+       help 
+         select if the panel do not need initialization
+config LCD_LD089WU1_MIPI
+       bool "mipi dsi lcd LD089WU1 1920X1200"
+config LCD_B080XAN02_MIPI
+       bool "mipi dsi lcd B080XAN02 1024X768"  
+endchoice
+
+
diff --git a/drivers/gpu/drm/rockchip/screen/Makefile b/drivers/gpu/drm/rockchip/screen/Makefile
new file mode 100644 (file)
index 0000000..bf42611
--- /dev/null
@@ -0,0 +1,24 @@
+obj-$(CONFIG_LCD_GENERAL) += lcd_general.o
+obj-$(CONFIG_LCD_LD089WU1_MIPI)   += lcd_LD089WU1_mipi.o
+obj-$(CONFIG_LCD_B080XAN02_MIPI)   += lcd_B080XAN02_mipi.o
+
+
+quiet_cmd_gen = GEN     $@
+      cmd_gen = cmp -s $< $@ || cp $< $@
+
+lcd-obj := $(filter lcd_%.o,$(obj-y))
+lcd-cfile := $(patsubst %.o,%.c,$(lcd-obj))
+lcd-cpath := $(src)/$(lcd-cfile)
+
+obj-y := $(filter-out $(lcd-obj),$(obj-y))
+
+$(obj)/lcd.h: $(lcd-cpath)  FORCE
+       $(call if_changed,gen)
+
+$(obj)/rk_screen.o: $(obj)/lcd.h
+obj-y += rk_screen.o
+
+clean-files := lcd.h
+
+
+
diff --git a/drivers/gpu/drm/rockchip/screen/lcd_B080XAN02_mipi.c b/drivers/gpu/drm/rockchip/screen/lcd_B080XAN02_mipi.c
new file mode 100755 (executable)
index 0000000..5d5997e
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __LCD_B080XAN02__
+#define __LCD_B080XAN02__
+
+#if defined(CONFIG_MIPI_DSI)
+#include "../transmitter/mipi_dsi.h"
+#endif
+#include <linux/delay.h>
+
+
+
+#define RK_SCREEN_INIT         1
+
+/* about mipi */
+#define MIPI_DSI_LANE 4
+#define MIPI_DSI_HS_CLK 528*1000000 //1000*1000000
+
+
+#if defined(RK_SCREEN_INIT)
+static struct rk29lcd_info *gLcd_info = NULL;
+
+int rk_lcd_init(void) {
+
+       u8 dcs[16] = {0};
+       if(dsi_is_active() != 1)
+               return -1;
+       /*below is changeable*/
+       dsi_enable_hs_clk(1);
+
+       dcs[0] = LPDT;
+       dcs[1] = dcs_exit_sleep_mode; 
+       dsi_send_dcs_packet(dcs, 2);
+       msleep(1);
+       dcs[0] = LPDT;
+       dcs[1] = dcs_set_display_on;
+       dsi_send_dcs_packet(dcs, 2);
+       msleep(10);
+       //dsi_enable_command_mode(0);
+       dsi_enable_video_mode(1);
+       
+       printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
+    return 0;
+}
+
+int rk_lcd_standby(u8 enable) {
+
+       u8 dcs[16] = {0};
+       if(dsi_is_active() != 1)
+               return -1;
+               
+       if(enable) {
+               /*below is changeable*/
+               dcs[0] = LPDT;
+               dcs[1] = dcs_set_display_off; 
+               dsi_send_dcs_packet(dcs, 2);
+               msleep(1);
+               dcs[0] = LPDT;
+               dcs[1] = dcs_enter_sleep_mode; 
+               dsi_send_dcs_packet(dcs, 2);
+               msleep(1);
+
+               printk("++++enable++++++++++++%s:%d\n", __func__, __LINE__);
+       
+       } else {
+               /*below is changeable*/
+               rk_lcd_init();
+               printk("++++++++++++++++%s:%d\n", __func__, __LINE__);  
+       }
+    return 0;
+}
+#endif
+
+#endif  
diff --git a/drivers/gpu/drm/rockchip/screen/lcd_LD089WU1_mipi.c b/drivers/gpu/drm/rockchip/screen/lcd_LD089WU1_mipi.c
new file mode 100644 (file)
index 0000000..30db8f0
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __LCD_LD089WU1__
+#define __LCD_LD089WU1__
+
+#if defined(CONFIG_MIPI_DSI)
+#include "../transmitter/mipi_dsi.h"
+#endif
+
+
+
+
+#define RK_SCREEN_INIT         1
+
+/* about mipi */
+#define MIPI_DSI_LANE 4
+#define MIPI_DSI_HS_CLK 1000*1000000
+
+#if defined(RK_SCREEN_INIT)
+static struct rk29lcd_info *gLcd_info = NULL;
+
+int rk_lcd_init(void) {
+
+       u8 dcs[16] = {0};
+       if(dsi_is_active() != 1)
+               return -1;
+               
+       /*below is changeable*/
+       dsi_enable_hs_clk(1);
+       dsi_enable_video_mode(0);
+       dsi_enable_command_mode(1);
+       dcs[0] = dcs_exit_sleep_mode; 
+       dsi_send_dcs_packet(dcs, 1);
+       msleep(1);
+       dcs[0] = dcs_set_display_on;
+       dsi_send_dcs_packet(dcs, 1);
+       msleep(10);
+       dsi_enable_command_mode(0);
+       dsi_enable_video_mode(1);
+       //printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
+};
+
+
+
+int rk_lcd_standby(u8 enable) {
+
+       u8 dcs[16] = {0};
+       if(dsi_is_active() != 1)
+               return -1;
+               
+       if(enable) {
+               dsi_enable_video_mode(0);
+               dsi_enable_command_mode(1);
+               /*below is changeable*/
+               dcs[0] = dcs_set_display_off; 
+               dsi_send_dcs_packet(dcs, 1);
+               msleep(1);
+               dcs[0] = dcs_enter_sleep_mode; 
+               dsi_send_dcs_packet(dcs, 1);
+               msleep(1);
+               //printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
+       
+       } else {
+               /*below is changeable*/
+               rk_lcd_init();
+               //printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
+       
+       }
+};
+#endif
+
+#endif  
diff --git a/drivers/gpu/drm/rockchip/screen/lcd_general.c b/drivers/gpu/drm/rockchip/screen/lcd_general.c
new file mode 100644 (file)
index 0000000..b57dc2c
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifndef __LCD_NULL__
+#define __LCD_NULL__
+
+
+
+#endif
+
diff --git a/drivers/gpu/drm/rockchip/screen/rk_screen.c b/drivers/gpu/drm/rockchip/screen/rk_screen.c
new file mode 100644 (file)
index 0000000..5579d28
--- /dev/null
@@ -0,0 +1,65 @@
+
+#include <linux/rk_fb.h>
+#include <linux/device.h>
+#include "lcd.h"
+
+static struct rk_screen *rk_screen;
+int  rk_fb_get_prmry_screen(struct rk_screen *screen)
+{
+       memcpy(screen, rk_screen, sizeof(struct rk_screen));
+       return 0;
+}
+
+
+size_t get_fb_size(void)
+{
+       
+}
+
+static int rk_screen_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Missing device tree node.\n");
+               return -EINVAL;
+       }
+       rk_screen = devm_kzalloc(&pdev->dev, sizeof(struct rk_screen), GFP_KERNEL);
+       if (!rk_screen) {
+               dev_err(&pdev->dev, "kmalloc for rk screen fail!");
+               return  -ENOMEM;
+       }
+       ret = rk_fb_prase_timing_dt(np,rk_screen);
+       dev_info(&pdev->dev, "rockchip screen probe %s\n",
+                               ret? "failed" : "success");
+       return ret;
+}
+
+static const struct of_device_id rk_screen_dt_ids[] = {
+       { .compatible = "rockchip,screen", },
+       {}
+};
+
+static struct platform_driver rk_screen_driver = {
+       .probe          = rk_screen_probe,
+       .driver         = {
+               .name   = "rk-screen",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(rk_screen_dt_ids),
+       },
+};
+
+static int __init rk_screen_init(void)
+{
+       return platform_driver_register(&rk_screen_driver);
+}
+
+static void __exit rk_screen_exit(void)
+{
+       platform_driver_unregister(&rk_screen_driver);
+}
+
+subsys_initcall_sync(rk_screen_init);
+module_exit(rk_screen_exit);
+
diff --git a/drivers/gpu/drm/rockchip/transmitter/Kconfig b/drivers/gpu/drm/rockchip/transmitter/Kconfig
new file mode 100644 (file)
index 0000000..edf8e3c
--- /dev/null
@@ -0,0 +1,72 @@
+
+menuconfig RK_TRSM
+       bool "RockChip display transmitter support"
+       depends on FB_ROCKCHIP
+
+config RK2928_LVDS
+       bool "RK2928/RK2926 lvds transmitter support"
+        depends on ARCH_RK2928 && RK_TRSM
+
+config RK3026_LVDS
+       depends on ARCH_RK3026 && RK_TRSM
+       bool "RK3026/RK3028A lvds transmitter support"
+       default y       
+
+config RK32_LVDS
+       bool "RK32 lvds transmitter support"
+       depends on RK_TRSM
+
+config RK610_LVDS
+       bool "RK610(Jetta) lvds transmitter support"
+       depends on MFD_RK610 && RK_TRSM 
+       help
+               Support Jetta(RK610) to output LCD1 and LVDS.
+
+config RK616_LVDS
+        bool "RK616(JettaB) lvds,lcd,scaler vido interface support"
+        depends on MFD_RK616 && RK_TRSM
+        help
+           RK616(Jetta B) LVDS,LCD,scaler transmitter support.
+               
+
+config DP_ANX6345
+       bool "RGB to DisplayPort transmitter anx6345,anx9804,anx9805 support"
+       depends on RK_TRSM
+
+config DP501
+       bool"RGB to DisplayPort transmitter dp501 support"
+       depends on RK_TRSM
+
+config RK32_DP
+       bool "RK32 RGB to DisplayPort transmitter support "
+       depends on RK_TRSM
+
+config MIPI_DSI
+       depends on RK_TRSM
+       bool "Rockchip MIPI DSI support"
+
+config TC358768_RGB2MIPI
+        tristate "toshiba TC358768 RGB to MIPI DSI"
+               depends on MIPI_DSI
+        help
+        "a chip that change RGB interface parallel signal into DSI serial signal"
+
+config SSD2828_RGB2MIPI
+        tristate "solomon SSD2828 RGB to MIPI DSI"
+               depends on MIPI_DSI
+        help
+        "a chip that change RGB interface parallel signal into DSI serial signal"
+
+config RK616_MIPI_DSI
+        tristate "Rockchip mipi dsi support"
+        depends on MIPI_DSI
+        help
+           Rockchip mipi dsi support.          
+
+                       
+config RK616_MIPI_DSI_RST
+       bool "Reset the rockchip mipi dsi"
+       depends on MFD_RK616 && RK616_MIPI_DSI && RK616_USE_MCLK_12M
+       default y
+       help
+        if you say y here: inset the hdmi, mipi lcd will be reset.  
diff --git a/drivers/gpu/drm/rockchip/transmitter/Makefile b/drivers/gpu/drm/rockchip/transmitter/Makefile
new file mode 100644 (file)
index 0000000..c03b0a7
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for display transmitter like lvds edp mipi
+#
+obj-$(CONFIG_RK2928_LVDS)       += rk2928_lvds.o
+obj-$(CONFIG_RK3026_LVDS)       += rk3026_lvds.o
+obj-$(CONFIG_RK610_LVDS)       += rk610_lcd.o
+obj-$(CONFIG_RK616_LVDS)        += rk616_lvds.o
+obj-y                          += rk32_lvds.o
+obj-$(CONFIG_DP_ANX6345)        += dp_anx6345.o
+obj-$(CONFIG_DP501)            += dp501.o
+obj-$(CONFIG_RK32_DP)          += rk32_dp.o rk32_dp_reg.o
+obj-$(CONFIG_MIPI_DSI)         += mipi_dsi.o 
+obj-$(CONFIG_RK616_MIPI_DSI)   += rk616_mipi_dsi.o
+obj-$(CONFIG_TC358768_RGB2MIPI) += tc358768.o
+obj-$(CONFIG_SSD2828_RGB2MIPI)  += ssd2828.o
+
diff --git a/drivers/gpu/drm/rockchip/transmitter/rk32_lvds.c b/drivers/gpu/drm/rockchip/transmitter/rk32_lvds.c
new file mode 100755 (executable)
index 0000000..d25c2c3
--- /dev/null
@@ -0,0 +1,323 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/rk_fb.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rockchip/grf.h>
+#include "rk32_lvds.h"
+
+//#define TTL_TO_LVDS 1
+static struct rk32_lvds *rk32_lvds;
+static int rk32_lvds_disable(void)
+{
+       struct rk32_lvds *lvds = rk32_lvds;
+       writel_relaxed(0x80008000, RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
+       writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_21); /*disable tx*/
+       writel_relaxed(0xff, lvds->regs + LVDS_CFG_REG_c); /*disable pll*/
+       clk_disable_unprepare(lvds->clk);
+       return 0;
+}
+
+static int rk32_lvds_en(void)
+{
+       struct rk32_lvds *lvds = rk32_lvds;
+       struct rk_screen *screen = &lvds->screen;
+       u32 h_bp = screen->mode.hsync_len + screen->mode.left_margin;
+       u32 i,j, val ;
+
+       clk_prepare_enable(lvds->clk);
+       screen->type = SCREEN_RGB;
+       
+       screen->lcdc_id = 1;
+       if (screen->lcdc_id == 1) /*lcdc1 = vop little,lcdc0 = vop big*/
+               val = LVDS_SEL_VOP_LIT | (LVDS_SEL_VOP_LIT << 16);
+       else
+               val = LVDS_SEL_VOP_LIT << 16;
+       writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
+
+       val = screen->lvds_format;
+       if (screen->type == SCREEN_DUAL_LVDS)
+               val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
+       else if(screen->type == SCREEN_LVDS)
+               val |= LVDS_CH0_EN;
+
+               //val |= LVDS_MSB;
+       else if (screen->type == SCREEN_RGB)
+               val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
+
+       if (h_bp & 0x01)
+               val |= LVDS_START_PHASE_RST_1;
+
+       val |= (screen->pin_dclk << 8) | (screen->pin_hsync << 9) |
+               (screen->pin_den << 10);
+       val |= 0xffff << 16;
+       //val = 0x08010801;
+       writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
+
+       if (screen->type == SCREEN_LVDS)
+               val = 0xbf;
+       else
+               val = 0x7f;
+#if 0
+       for(i=0;i<0x200;){
+               val  = readl_relaxed(lvds->regs + i);
+               printk("0x%08x:0x%08x  ",i,val);
+               i += 4;
+               if(i % 16 == 0)
+                       printk("\n");
+       }
+#endif 
+       #ifdef  TTL_TO_LVDS // 0 ttl  1 lvds
+       val = 0x007f007f;//0x1<<6 |0x1 <<4;
+       writel_relaxed(val, RK_GRF_VIRT + 0xc);
+
+       
+       lvds_writel(lvds, LVDS_CH0_REG_0, 0x7f);
+       lvds_writel(lvds, LVDS_CH0_REG_1, 0x40);
+       lvds_writel(lvds, LVDS_CH0_REG_2, 0x00);
+
+       if (screen->type == SCREEN_RGB)
+               val = 0x1f;
+       else
+               val = 0x00;
+       lvds_writel(lvds, LVDS_CH0_REG_4, 0x3f);
+       lvds_writel(lvds, LVDS_CH0_REG_5, 0x3f);
+       lvds_writel(lvds, LVDS_CH0_REG_3, 0x46);
+       lvds_writel(lvds, LVDS_CH0_REG_d, 0x0a);
+       lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB  45:MSB*/
+       writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_c); /*eanble pll*/
+       writel_relaxed(0x92, lvds->regs + LVDS_CFG_REG_21); /*enable tx*/
+
+       lvds_writel(lvds, 0x100, 0x7f);
+       lvds_writel(lvds, 0x104, 0x40);
+       lvds_writel(lvds, 0x108, 0x00);
+       lvds_writel(lvds, 0x10c, 0x46);
+       lvds_writel(lvds, 0x110, 0x3f);
+       lvds_writel(lvds, 0x114, 0x3f);
+       lvds_writel(lvds, 0x134, 0x0a);
+       #else
+       val  = readl_relaxed(lvds->regs + 0x88);
+       printk("0x88:0x%x\n",val);
+
+       lvds_writel(lvds, LVDS_CH0_REG_0, 0xbf);
+       lvds_writel(lvds, LVDS_CH0_REG_1, 0x3f);//  3f
+       lvds_writel(lvds, LVDS_CH0_REG_2, 0xfe);
+       lvds_writel(lvds, LVDS_CH0_REG_3, 0x46);//0x46
+       lvds_writel(lvds, LVDS_CH0_REG_4, 0x00);
+       //lvds_writel(lvds, LVDS_CH0_REG_9, 0x20);
+       //lvds_writel(lvds, LVDS_CH0_REG_d, 0x4b);
+       //lvds_writel(lvds, LVDS_CH0_REG_f, 0x0d);
+       lvds_writel(lvds, LVDS_CH0_REG_d, 0x0a);//0a
+       lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB  45:MSB*/
+       //lvds_writel(lvds, 0x24,0x20);
+       //writel_relaxed(0x23, lvds->regs + 0x88);
+       writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_c); /*eanble pll*/
+       writel_relaxed(0x92, lvds->regs + LVDS_CFG_REG_21); /*enable tx*/
+
+
+       //lvds_writel(lvds, 0x100, 0xbf);
+       //lvds_writel(lvds, 0x104, 0x3f);
+       //lvds_writel(lvds, 0x108, 0xfe);
+       //lvds_writel(lvds, 0x10c, 0x46); //0x46
+       //lvds_writel(lvds, 0x110, 0x00);
+       //lvds_writel(lvds, 0x114, 0x00);
+       //lvds_writel(lvds, 0x134, 0x0a);
+
+       #endif
+#if 0
+       for(i=0;i<100;i++){
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               printk("write LVDS_CH0_REG_20 :0x40\n");
+               //writel_relaxed(0x10, lvds->regs + LVDS_CFG_REG_c);
+               lvds_writel(lvds, LVDS_CH0_REG_20,0x40);/* 44:LSB  45:MSB*/
+               val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_20);
+               printk("read back LVDS_CH0_REG_20:0x%x\n",val);
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               mdelay(1000);
+               printk("write LVDS_CH0_REG_20 :0x44\n");
+               lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB  45:MSB*/
+               val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_20);
+               printk("read back LVDS_CH0_REG_20:0x%x\n",val);
+       }
+#endif 
+       //while(1)
+#if 0
+       {
+       val  = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
+       printk("RK3288_GRF_SOC_CON6:0x%x\n",val);
+       val  = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
+       printk("RK3288_GRF_SOC_CON7:0x%x\n",val);
+       val  = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON15);
+       printk("RK3288_GRF_SOC_CON15:0x%x\n",val);
+       
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_0);
+       printk("LVDS_CH0_REG_0:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_1);
+       printk("LVDS_CH0_REG_1:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_2);
+       printk("LVDS_CH0_REG_2:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_3);
+       printk("LVDS_CH0_REG_3:0x%x\n",val);
+       
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_4);
+       printk("LVDS_CH0_REG_4:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_5);
+       printk("LVDS_CH0_REG_5:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_d);
+       printk("LVDS_CH0_REG_d:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CH0_REG_f);
+               printk("LVDS_CH0_REG_f:0x%x\n",val);
+
+       
+       val  = readl_relaxed(lvds->regs + LVDS_CFG_REG_c);
+       printk("LVDS_CFG_REG_c:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + LVDS_CFG_REG_21);
+       printk("LVDS_CFG_REG_21:0x%x\n",val);
+       val  = readl_relaxed(lvds->regs + 0x100);
+       printk("0x100:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + 0x104);
+       printk("0x104:0x%x\n",val);
+               val  = readl_relaxed(lvds->regs + 0x108);
+       printk("0x108:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + 0x10c);
+       printk("0x10c:0x%x\n",val);
+       
+       val  = readl_relaxed(lvds->regs + 0x110);
+       printk("0x110:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + 0x114);
+       printk("0x114:0x%x\n",val);
+               val  = readl_relaxed(lvds->regs + 0x118);
+       printk("0x118:0x%x\n",val);
+
+       val  = readl_relaxed(lvds->regs + 0x11c);
+       printk("0x11c:0x%x\n",val);     
+       mdelay(1000);
+               }
+
+       for(i=0;i<0x200;){
+               val  = readl_relaxed(lvds->regs + i);
+               printk("0x%08x:0x%08x  ",i,val);
+               i += 4;
+               if(i % 16 == 0)
+                       printk("\n");
+       }
+#endif
+       return 0;
+}
+
+
+
+static struct rk_fb_trsm_ops trsm_lvds_ops = {
+       .enable = rk32_lvds_en,
+       .disable = rk32_lvds_disable,
+};
+
+static int rk32_lvds_probe(struct platform_device *pdev)
+{
+       struct rk32_lvds *lvds;
+       struct resource *res;
+       struct device_node *np = pdev->dev.of_node;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Missing device tree node.\n");
+               return -EINVAL;
+       }
+
+       lvds = devm_kzalloc(&pdev->dev, sizeof(struct rk32_lvds), GFP_KERNEL);
+       if (!lvds) {
+               dev_err(&pdev->dev, "no memory for state\n");
+               return -ENOMEM;
+       }
+       lvds->dev = &pdev->dev;
+       rk_fb_get_prmry_screen(&lvds->screen);
+       if ((lvds->screen.type != SCREEN_RGB) && 
+               (lvds->screen.type != SCREEN_LVDS) &&
+               (lvds->screen.type != SCREEN_DUAL_LVDS)) {
+               dev_err(&pdev->dev, "screen is not lvds/rgb!\n");
+               return -EINVAL;
+       }
+       platform_set_drvdata(pdev, lvds);
+       dev_set_name(lvds->dev, "rk32-lvds");
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       lvds->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(lvds->regs)) {
+               dev_err(&pdev->dev, "ioremap reg failed\n");
+               return PTR_ERR(lvds->regs);
+       }
+       lvds->clk = devm_clk_get(&pdev->dev,NULL);
+       if (IS_ERR(lvds->clk)) {
+               dev_err(&pdev->dev, "get clk failed\n");
+               return PTR_ERR(lvds->clk);
+       }
+       rk32_lvds = lvds;
+       rk_fb_trsm_ops_register(&trsm_lvds_ops,SCREEN_LVDS);
+       dev_info(&pdev->dev, "rk32 lvds driver probe success\n");
+
+       return 0;
+}
+
+static void rk32_lvds_shutdown(struct platform_device *pdev)
+{
+
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rk32_lvds_dt_ids[] = {
+       {.compatible = "rockchip, rk32-lvds",},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, rk32_lvds_dt_ids);
+#endif
+
+static struct platform_driver rk32_lvds_driver = {
+       .probe = rk32_lvds_probe,
+       .driver = {
+                  .name = "rk32-lvds",
+                  .owner = THIS_MODULE,
+#if defined(CONFIG_OF)
+                  .of_match_table = of_match_ptr(rk32_lvds_dt_ids),
+#endif
+       },
+       .shutdown = rk32_lvds_shutdown,
+};
+
+static int __init rk32_lvds_module_init(void)
+{
+       return platform_driver_register(&rk32_lvds_driver);
+}
+
+static void __exit rk32_lvds_module_exit(void)
+{
+
+}
+
+fs_initcall(rk32_lvds_module_init);
+module_exit(rk32_lvds_module_exit);
+
diff --git a/drivers/gpu/drm/rockchip/transmitter/rk32_lvds.h b/drivers/gpu/drm/rockchip/transmitter/rk32_lvds.h
new file mode 100755 (executable)
index 0000000..d2f8d56
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __RK32_LVDS__
+#define __RK32_LVDS__
+
+#define LVDS_CH0_REG_0                 0x00
+#define LVDS_CH0_REG_1                 0x04
+#define LVDS_CH0_REG_2                 0x08
+#define LVDS_CH0_REG_3                 0x0c
+#define LVDS_CH0_REG_4                 0x10
+#define LVDS_CH0_REG_5                 0x14
+#define LVDS_CH0_REG_9                 0x24
+#define LVDS_CFG_REG_c                 0x30
+#define LVDS_CH0_REG_d                 0x34
+#define LVDS_CH0_REG_f                 0x3c
+#define LVDS_CH0_REG_20                        0x80
+#define LVDS_CFG_REG_21                        0x84
+
+#define LVDS_SEL_VOP_LIT               (1 << 3)
+
+#define LVDS_FMT_MASK                  (0x07 << 16)
+#define LVDS_MSB                       (0x01 << 3)
+#define LVDS_DUAL                      (0x01 << 4)
+#define LVDS_FMT_1                     (0x01 << 5)
+#define LVDS_TTL_EN                    (0x01 << 6)
+#define LVDS_START_PHASE_RST_1         (0x01 << 7)
+#define LVDS_DCLK_INV                  (0x01 << 8)
+#define LVDS_CH0_EN                    (0x01 << 11)
+#define LVDS_CH1_EN                    (0x01 << 12)
+#define LVDS_PWRDN                     (0x01 << 15)
+
+struct rk32_lvds {
+       struct device           *dev;
+       void __iomem            *regs;
+       struct clk              *clk; /*phb clk*/
+       struct rk_screen        screen;
+};
+
+static int inline lvds_writel(struct rk32_lvds *lvds, u32 offset, u32 val)
+{
+       writel_relaxed(val, lvds->regs + offset);
+       //if (lvds->screen.type == SCREEN_DUAL_LVDS)
+               writel_relaxed(val, lvds->regs + offset + 0x100);
+       return 0;
+}
+#endif
index 63d17ee9eb488c336ad55521f346dc1c2703c4c4..872d0000956ef6889acb62a65acdccfb031f7ea2 100644 (file)
@@ -204,7 +204,7 @@ int drm_err(const char *func, const char *format, ...);
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#if DRM_DEBUG_CODE
+#if 0// DRM_DEBUG_CODE
 #define DRM_DEBUG(fmt, args...)                                                \
        do {                                                            \
                drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME,              \
diff --git a/include/drm/rockchip_drm.h b/include/drm/rockchip_drm.h
new file mode 100644 (file)
index 0000000..9339c44
--- /dev/null
@@ -0,0 +1,100 @@
+/* rockchip_drm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ *     Inki Dae <inki.dae@samsung.com>
+ *     Joonyoung Shim <jy0922.shim@samsung.com>
+ *     Seung-Woo Kim <sw0312.kim@samsung.com>
+ *
+ * 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.
+ */
+#ifndef _rockchip_DRM_H_
+#define _rockchip_DRM_H_
+
+#include <uapi/drm/rockchip_drm.h>
+
+/**
+ * A structure for lcd panel information.
+ *
+ * @timing: default video mode for initializing
+ * @width_mm: physical size of lcd width.
+ * @height_mm: physical size of lcd height.
+ */
+struct rockchip_drm_panel_info {
+       struct fb_videomode timing;
+       u32 width_mm;
+       u32 height_mm;
+};
+
+/**
+ * Platform Specific Structure for DRM based FIMD.
+ *
+ * @panel: default panel info for initializing
+ * @default_win: default window layer number to be used for UI.
+ * @bpp: default bit per pixel.
+ */
+struct rockchip_drm_fimd_pdata {
+       struct rockchip_drm_panel_info panel;
+       u32                             vidcon0;
+       u32                             vidcon1;
+       unsigned int                    default_win;
+       unsigned int                    bpp;
+};
+
+/**
+ * Platform Specific Structure for DRM based HDMI.
+ *
+ * @hdmi_dev: device point to specific hdmi driver.
+ * @mixer_dev: device point to specific mixer driver.
+ *
+ * this structure is used for common hdmi driver and each device object
+ * would be used to access specific device driver(hdmi or mixer driver)
+ */
+struct rockchip_drm_common_hdmi_pd {
+       struct device *hdmi_dev;
+       struct device *mixer_dev;
+};
+
+/**
+ * Platform Specific Structure for DRM based HDMI core.
+ *
+ * @is_v13: set if hdmi version 13 is.
+ * @cfg_hpd: function pointer to configure hdmi hotplug detection pin
+ * @get_hpd: function pointer to get value of hdmi hotplug detection pin
+ */
+struct rockchip_drm_hdmi_pdata {
+       bool is_v13;
+       void (*cfg_hpd)(bool external);
+       int (*get_hpd)(void);
+};
+
+/**
+ * Platform Specific Structure for DRM based IPP.
+ *
+ * @inv_pclk: if set 1. invert pixel clock
+ * @inv_vsync: if set 1. invert vsync signal for wb
+ * @inv_href: if set 1. invert href signal
+ * @inv_hsync: if set 1. invert hsync signal for wb
+ */
+struct rockchip_drm_ipp_pol {
+       unsigned int inv_pclk;
+       unsigned int inv_vsync;
+       unsigned int inv_href;
+       unsigned int inv_hsync;
+};
+
+/**
+ * Platform Specific Structure for DRM based FIMC.
+ *
+ * @pol: current hardware block polarity settings.
+ * @clk_rate: current hardware clock rate.
+ */
+struct rockchip_drm_fimc_pdata {
+       struct rockchip_drm_ipp_pol pol;
+       int clk_rate;
+};
+
+#endif /* _rockchip_DRM_H_ */
diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h
new file mode 100644 (file)
index 0000000..8edac44
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ *
+ * Copyright (C) ROCKCHIP, Inc.
+ *Author:yzq<yzq@rock-chips.com>
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _UAPI_ROCKCHIP_DRM_H_
+#define _UAPI_ROCKCHIP_DRM_H_
+
+#include <drm/drm.h>
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ *     - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ *     - this handle will be set by gem module of kernel side.
+ */
+struct drm_rockchip_gem_create {
+       uint64_t size;
+       unsigned int flags;
+       unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ *     - this value should be set by user.
+ */
+struct drm_rockchip_gem_map_off {
+       unsigned int handle;
+       unsigned int pad;
+       uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ *     - this variable would be filled by exynos gem module
+ *     of kernel side with user virtual address which is allocated
+ *     by do_mmap().
+ */
+struct drm_rockchip_gem_mmap {
+       unsigned int handle;
+       unsigned int pad;
+       uint64_t size;
+       uint64_t mapped;
+};
+
+/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ *     this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ *     be set by driver.
+ */
+struct drm_rockchip_gem_info {
+       unsigned int handle;
+       unsigned int flags;
+       uint64_t size;
+};
+
+/**
+ * A structure for user connection request of virtual display.
+ *
+ * @connection: indicate whether doing connetion or not by user.
+ * @extensions: if this value is 1 then the vidi driver would need additional
+ *     128bytes edid data.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_rockchip_vidi_connection {
+       unsigned int connection;
+       unsigned int extensions;
+       uint64_t edid;
+};
+
+/* memory type definitions. */
+enum e_drm_rockchip_gem_mem_type {
+       /* Physically Continuous memory and used as default. */
+       ROCKCHIP_BO_CONTIG      = 0 << 0,
+       /* Physically Non-Continuous memory. */
+       ROCKCHIP_BO_NONCONTIG   = 1 << 0,
+       /* non-cachable mapping and used as default. */
+       ROCKCHIP_BO_NONCACHABLE = 0 << 1,
+       /* cachable mapping. */
+       ROCKCHIP_BO_CACHABLE    = 1 << 1,
+       /* write-combine mapping. */
+       ROCKCHIP_BO_WC          = 1 << 2,
+       ROCKCHIP_BO_MASK                = ROCKCHIP_BO_NONCONTIG | ROCKCHIP_BO_CACHABLE |
+                                       ROCKCHIP_BO_WC
+};
+
+struct drm_rockchip_g2d_get_ver {
+       __u32   major;
+       __u32   minor;
+};
+
+struct drm_rockchip_g2d_cmd {
+       __u32   offset;
+       __u32   data;
+};
+
+enum drm_rockchip_g2d_buf_type {
+       G2D_BUF_USERPTR = 1 << 31,
+};
+
+enum drm_rockchip_g2d_event_type {
+       G2D_EVENT_NOT,
+       G2D_EVENT_NONSTOP,
+       G2D_EVENT_STOP,         /* not yet */
+};
+
+struct drm_rockchip_g2d_userptr {
+       unsigned long userptr;
+       unsigned long size;
+};
+
+struct drm_rockchip_g2d_set_cmdlist {
+       __u64                                   cmd;
+       __u64                                   cmd_buf;
+       __u32                                   cmd_nr;
+       __u32                                   cmd_buf_nr;
+
+       /* for g2d event */
+       __u64                                   event_type;
+       __u64                                   user_data;
+};
+
+struct drm_rockchip_g2d_exec {
+       __u64                                   async;
+};
+
+enum drm_rockchip_ops_id {
+       ROCKCHIP_DRM_OPS_SRC,
+       ROCKCHIP_DRM_OPS_DST,
+       ROCKCHIP_DRM_OPS_MAX,
+};
+
+struct drm_rockchip_sz {
+       __u32   hsize;
+       __u32   vsize;
+};
+
+struct drm_rockchip_pos {
+       __u32   x;
+       __u32   y;
+       __u32   w;
+       __u32   h;
+};
+
+enum drm_rockchip_flip {
+       ROCKCHIP_DRM_FLIP_NONE = (0 << 0),
+       ROCKCHIP_DRM_FLIP_VERTICAL = (1 << 0),
+       ROCKCHIP_DRM_FLIP_HORIZONTAL = (1 << 1),
+       ROCKCHIP_DRM_FLIP_BOTH = ROCKCHIP_DRM_FLIP_VERTICAL |
+                       ROCKCHIP_DRM_FLIP_HORIZONTAL,
+};
+
+enum drm_rockchip_degree {
+       ROCKCHIP_DRM_DEGREE_0,
+       ROCKCHIP_DRM_DEGREE_90,
+       ROCKCHIP_DRM_DEGREE_180,
+       ROCKCHIP_DRM_DEGREE_270,
+};
+
+enum drm_rockchip_planer {
+       ROCKCHIP_DRM_PLANAR_Y,
+       ROCKCHIP_DRM_PLANAR_CB,
+       ROCKCHIP_DRM_PLANAR_CR,
+       ROCKCHIP_DRM_PLANAR_MAX,
+};
+
+/**
+ * A structure for ipp supported property list.
+ *
+ * @version: version of this structure.
+ * @ipp_id: id of ipp driver.
+ * @count: count of ipp driver.
+ * @writeback: flag of writeback supporting.
+ * @flip: flag of flip supporting.
+ * @degree: flag of degree information.
+ * @csc: flag of csc supporting.
+ * @crop: flag of crop supporting.
+ * @scale: flag of scale supporting.
+ * @refresh_min: min hz of refresh.
+ * @refresh_max: max hz of refresh.
+ * @crop_min: crop min resolution.
+ * @crop_max: crop max resolution.
+ * @scale_min: scale min resolution.
+ * @scale_max: scale max resolution.
+ */
+struct drm_rockchip_ipp_prop_list {
+       __u32   version;
+       __u32   ipp_id;
+       __u32   count;
+       __u32   writeback;
+       __u32   flip;
+       __u32   degree;
+       __u32   csc;
+       __u32   crop;
+       __u32   scale;
+       __u32   refresh_min;
+       __u32   refresh_max;
+       __u32   reserved;
+       struct drm_rockchip_sz  crop_min;
+       struct drm_rockchip_sz  crop_max;
+       struct drm_rockchip_sz  scale_min;
+       struct drm_rockchip_sz  scale_max;
+};
+
+/**
+ * A structure for ipp config.
+ *
+ * @ops_id: property of operation directions.
+ * @flip: property of mirror, flip.
+ * @degree: property of rotation degree.
+ * @fmt: property of image format.
+ * @sz: property of image size.
+ * @pos: property of image position(src-cropped,dst-scaler).
+ */
+struct drm_rockchip_ipp_config {
+       enum drm_rockchip_ops_id ops_id;
+       enum drm_rockchip_flip  flip;
+       enum drm_rockchip_degree        degree;
+       __u32   fmt;
+       struct drm_rockchip_sz  sz;
+       struct drm_rockchip_pos pos;
+};
+
+enum drm_rockchip_ipp_cmd {
+       IPP_CMD_NONE,
+       IPP_CMD_M2M,
+       IPP_CMD_WB,
+       IPP_CMD_OUTPUT,
+       IPP_CMD_MAX,
+};
+
+/**
+ * A structure for ipp property.
+ *
+ * @config: source, destination config.
+ * @cmd: definition of command.
+ * @ipp_id: id of ipp driver.
+ * @prop_id: id of property.
+ * @refresh_rate: refresh rate.
+ */
+struct drm_rockchip_ipp_property {
+       struct drm_rockchip_ipp_config config[ROCKCHIP_DRM_OPS_MAX];
+       enum drm_rockchip_ipp_cmd       cmd;
+       __u32   ipp_id;
+       __u32   prop_id;
+       __u32   refresh_rate;
+};
+
+enum drm_rockchip_ipp_buf_type {
+       IPP_BUF_ENQUEUE,
+       IPP_BUF_DEQUEUE,
+};
+
+/**
+ * A structure for ipp buffer operations.
+ *
+ * @ops_id: operation directions.
+ * @buf_type: definition of buffer.
+ * @prop_id: id of property.
+ * @buf_id: id of buffer.
+ * @handle: Y, Cb, Cr each planar handle.
+ * @user_data: user data.
+ */
+struct drm_rockchip_ipp_queue_buf {
+       enum drm_rockchip_ops_id        ops_id;
+       enum drm_rockchip_ipp_buf_type  buf_type;
+       __u32   prop_id;
+       __u32   buf_id;
+       __u32   handle[ROCKCHIP_DRM_PLANAR_MAX];
+       __u32   reserved;
+       __u64   user_data;
+};
+
+enum drm_rockchip_ipp_ctrl {
+       IPP_CTRL_PLAY,
+       IPP_CTRL_STOP,
+       IPP_CTRL_PAUSE,
+       IPP_CTRL_RESUME,
+       IPP_CTRL_MAX,
+};
+
+/**
+ * A structure for ipp start/stop operations.
+ *
+ * @prop_id: id of property.
+ * @ctrl: definition of control.
+ */
+struct drm_rockchip_ipp_cmd_ctrl {
+       __u32   prop_id;
+       enum drm_rockchip_ipp_ctrl      ctrl;
+};
+
+#define DRM_ROCKCHIP_GEM_CREATE                0x00
+#define DRM_ROCKCHIP_GEM_MAP_OFFSET    0x01
+#define DRM_ROCKCHIP_GEM_MMAP          0x02
+/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
+#define DRM_ROCKCHIP_GEM_GET           0x04
+#define DRM_ROCKCHIP_VIDI_CONNECTION   0x07
+
+/* G2D */
+#define DRM_ROCKCHIP_G2D_GET_VER               0x20
+#define DRM_ROCKCHIP_G2D_SET_CMDLIST   0x21
+#define DRM_ROCKCHIP_G2D_EXEC          0x22
+
+/* IPP - Image Post Processing */
+#define DRM_ROCKCHIP_IPP_GET_PROPERTY  0x30
+#define DRM_ROCKCHIP_IPP_SET_PROPERTY  0x31
+#define DRM_ROCKCHIP_IPP_QUEUE_BUF     0x32
+#define DRM_ROCKCHIP_IPP_CMD_CTRL      0x33
+
+#define DRM_IOCTL_ROCKCHIP_GEM_CREATE          DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET      DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MMAP    DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_GEM_MMAP, struct drm_rockchip_gem_mmap)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_GET     DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_GEM_GET,   struct drm_rockchip_gem_info)
+
+#define DRM_IOCTL_ROCKCHIP_VIDI_CONNECTION     DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_VIDI_CONNECTION, struct drm_rockchip_vidi_connection)
+
+#define DRM_IOCTL_ROCKCHIP_G2D_GET_VER         DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_G2D_GET_VER, struct drm_rockchip_g2d_get_ver)
+#define DRM_IOCTL_ROCKCHIP_G2D_SET_CMDLIST     DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_G2D_SET_CMDLIST, struct drm_rockchip_g2d_set_cmdlist)
+#define DRM_IOCTL_ROCKCHIP_G2D_EXEC            DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_G2D_EXEC, struct drm_rockchip_g2d_exec)
+
+#define DRM_IOCTL_ROCKCHIP_IPP_GET_PROPERTY    DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_IPP_GET_PROPERTY, struct drm_rockchip_ipp_prop_list)
+#define DRM_IOCTL_ROCKCHIP_IPP_SET_PROPERTY    DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_IPP_SET_PROPERTY, struct drm_rockchip_ipp_property)
+#define DRM_IOCTL_ROCKCHIP_IPP_QUEUE_BUF       DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_IPP_QUEUE_BUF, struct drm_rockchip_ipp_queue_buf)
+#define DRM_IOCTL_ROCKCHIP_IPP_CMD_CTRL                DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_ROCKCHIP_IPP_CMD_CTRL, struct drm_rockchip_ipp_cmd_ctrl)
+
+/* ROCKCHIP specific events */
+#define DRM_ROCKCHIP_G2D_EVENT         0x80000000
+#define DRM_ROCKCHIP_IPP_EVENT         0x80000001
+
+struct drm_rockchip_g2d_event {
+       struct drm_event        base;
+       __u64                   user_data;
+       __u32                   tv_sec;
+       __u32                   tv_usec;
+       __u32                   cmdlist_no;
+       __u32                   reserved;
+};
+
+struct drm_rockchip_ipp_event {
+       struct drm_event        base;
+       __u64                   user_data;
+       __u32                   tv_sec;
+       __u32                   tv_usec;
+       __u32                   prop_id;
+       __u32                   reserved;
+       __u32                   buf_id[ROCKCHIP_DRM_OPS_MAX];
+};
+
+#endif /* _UAPI_ROCKCHIP_DRM_H_ */
index e7a4db4b1347ff83de6eec5a2c9cc34b36d592af..3e64b4144c7966585c3ee6acd7f1a03fdf2d711f 100644 (file)
@@ -75,7 +75,7 @@ struct display_timing {
        struct timing_entry vsync_len;          /* ver. sync len */
 
        enum display_flags flags;               /* display flags */
-#if defined(CONFIG_FB_ROCKCHIP)
+#if defined(CONFIG_FB_ROCKCHIP) || defined(CONFIG_DRM_ROCKCHIP)
        u16 screen_type;                        /*screen type*/
        u16 lvds_format;                        /*lvds data format for lvds screen*/
        u16 face;                               /*display output  interface format:24bit 18bit 16bit*/