video: rockchip: support VOP-LITE controller driver
authorWenlong Zhuang <daisen.zhuang@rock-chips.com>
Tue, 29 Dec 2015 06:42:17 +0000 (14:42 +0800)
committerGerrit Code Review <gerrit@rock-chips.com>
Tue, 23 Feb 2016 01:34:06 +0000 (09:34 +0800)
Rockchip SoC such RK3366 has VOP-LITE controller. This patch
supports VOP-LITE driver base on Rockchip SoC Chip.

Change-Id: I64ea2307609530f7dc0dbe6b1c9b3059d1cf821d
Signed-off-by: Wenlong Zhuang <daisen.zhuang@rock-chips.com>
drivers/video/rockchip/lcdc/Kconfig
drivers/video/rockchip/lcdc/Makefile
drivers/video/rockchip/lcdc/rk_vop_lite.c [new file with mode: 0644]
drivers/video/rockchip/lcdc/rk_vop_lite.h [new file with mode: 0644]

index bec8730681800cec6372b04e31991835eae00409..9a9ebf490fb713a0ae7106fc070e285c0dfb46f9 100644 (file)
@@ -56,3 +56,10 @@ config LCDC_RK322X
        depends on FB_ROCKCHIP
        help
          Driver for rk322x lcdc.There are one lcd controllers on rk322x
+
+config LCDC_LITE_RK3X
+       bool "rk lcdc lite support"
+       depends on FB_ROCKCHIP
+       help
+         Driver for rk lcdc lite.There are one lcd controllers on rk3366 or
+         on other chips in future
index 0cbe7f332104f6fa7276d3e197339d30069e0fb2..b751d1c2d1f9ff381d36414e7daa06fec8ce2fb9 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_LCDC_RK3036) += rk3036_lcdc.o
 obj-$(CONFIG_LCDC_RK312X) += rk312x_lcdc.o
 obj-$(CONFIG_LCDC_RK3368) += rk3368_lcdc.o
 obj-$(CONFIG_LCDC_RK322X) += rk322x_lcdc.o
+obj-$(CONFIG_LCDC_LITE_RK3X) += rk_vop_lite.o
diff --git a/drivers/video/rockchip/lcdc/rk_vop_lite.c b/drivers/video/rockchip/lcdc/rk_vop_lite.c
new file mode 100644 (file)
index 0000000..bd1e824
--- /dev/null
@@ -0,0 +1,2623 @@
+/*
+ * rockchip VOP(Video Output Processer) hardware driver.
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ * Author: WenLong Zhuang <daisen.zhuang@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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/rockchip-iovmm.h>
+#include <asm/div64.h>
+#include <linux/uaccess.h>
+#include <linux/rockchip/cpu.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rockchip/grf.h>
+#include <linux/rockchip/common.h>
+#include <dt-bindings/clock/rk_system_status.h>
+
+#include "rk_vop_lite.h"
+
+static int dbg_thresd;
+module_param(dbg_thresd, int, S_IRUGO | S_IWUSR);
+
+#define DBG(level, x...) do {                  \
+       if (unlikely(dbg_thresd >= level))      \
+               pr_info(x);\
+       } while (0)
+
+#define to_vop_dev(drv) container_of(drv, struct vop_device, driver)
+
+static struct rk_lcdc_win vop_win[] = {
+       { .name = "win0", .id = 0},
+       { .name = "win1", .id = 1},
+       { .name = "hwc",  .id = 2}
+};
+
+static int vop_set_bcsh(struct rk_lcdc_driver *dev_drv, bool enable);
+
+static int vop_clk_enable(struct vop_device *vop_dev)
+{
+       if (!vop_dev->clk_on) {
+               pm_runtime_get_sync(vop_dev->dev);
+
+               clk_enable(vop_dev->hclk);
+               clk_enable(vop_dev->aclk);
+               clk_enable(vop_dev->dclk);
+               spin_lock(&vop_dev->reg_lock);
+               vop_dev->clk_on = 1;
+               spin_unlock(&vop_dev->reg_lock);
+       }
+
+       return 0;
+}
+
+static int vop_clk_disable(struct vop_device *vop_dev)
+{
+       if (vop_dev->clk_on) {
+               spin_lock(&vop_dev->reg_lock);
+               vop_dev->clk_on = 0;
+               spin_unlock(&vop_dev->reg_lock);
+               clk_disable(vop_dev->dclk);
+               clk_disable(vop_dev->aclk);
+               clk_disable(vop_dev->hclk);
+
+               pm_runtime_put(vop_dev->dev);
+       }
+
+       return 0;
+}
+
+static int vop_irq_enable(struct vop_device *vop_dev)
+{
+       u64 val;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_mask_writel(vop_dev, INTR_CLEAR, INTR_MASK, INTR_MASK);
+
+               val = INTR_FS0 | INTR_FS1 | INTR_LINE_FLAG0 | INTR_LINE_FLAG1 |
+                       INTR_BUS_ERROR | INTR_WIN0_EMPTY | INTR_WIN1_EMPTY |
+                       INTR_DSP_HOLD_VALID;
+               vop_mask_writel(vop_dev, INTR_EN, INTR_MASK, val);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_irq_disable(struct vop_device *vop_dev)
+{
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               spin_lock(&vop_dev->reg_lock);
+               vop_writel(vop_dev, INTR_EN, 0xffff0000);
+               vop_writel(vop_dev, INTR_CLEAR, 0xffffffff);
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_standby_enable(struct vop_device *vop_dev)
+{
+       u64 val;
+       int ret;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_dev->sync.stdbyfin.done = 0;
+
+               vop_msk_reg(vop_dev, DSP_CTRL2, V_DSP_BLANK_EN(1));
+               /*vop_mask_writel(vop_dev, INTR_CLEAR0, INTR_MASK, INTR_MASK);*/
+               val = V_IMD_VOP_STANDBY_EN(1) | V_IMD_VOP_DMA_STOP(1) |
+                       V_IMD_DSP_OUT_ZERO(1);
+               vop_msk_reg(vop_dev, SYS_CTRL2, val);
+               vop_cfg_done(vop_dev);
+               spin_unlock(&vop_dev->reg_lock);
+
+               /* wait for standby hold valid */
+               ret = vop_completion_timeout_ms(&vop_dev->sync.stdbyfin,
+                                               vop_dev->sync.stdbyfin_to);
+               if (!ret) {
+                       dev_err(vop_dev->dev,
+                               "wait standby hold valid timeout %dms\n",
+                               vop_dev->sync.stdbyfin_to);
+                       return -ETIMEDOUT;
+               }
+       } else {
+               spin_unlock(&vop_dev->reg_lock);
+       }
+
+       return 0;
+}
+
+static int vop_standby_disable(struct vop_device *vop_dev)
+{
+       u64 val;
+       int ret;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_dev->sync.frmst.done = 0;
+               val = V_IMD_VOP_STANDBY_EN(0) | V_IMD_VOP_DMA_STOP(0) |
+                       V_IMD_DSP_OUT_ZERO(0);
+               vop_msk_reg(vop_dev, SYS_CTRL2, val);
+               vop_msk_reg(vop_dev, DSP_CTRL2, V_DSP_BLANK_EN(0));
+               vop_cfg_done(vop_dev);
+               spin_unlock(&vop_dev->reg_lock);
+
+               /* win address maybe effect after next frame start,
+                * but mmu maybe effect right now, so need wait frame start
+                */
+               ret = vop_completion_timeout_ms(&vop_dev->sync.frmst,
+                                               vop_dev->sync.frmst_to);
+               if (!ret) {
+                       dev_err(vop_dev->dev, "wait frame start timeout %dms\n",
+                               vop_dev->sync.frmst_to);
+                       return -ETIMEDOUT;
+               }
+       } else {
+               spin_unlock(&vop_dev->reg_lock);
+       }
+
+       return 0;
+}
+
+static int vop_mmu_enable(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (!dev_drv->iommu_enabled || !dev_drv->mmu_dev) {
+               pr_debug("%s: VOP iommu is disabled or not find mmu dev\n",
+                        __func__);
+               return -ENODEV;
+       }
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               if (!vop_dev->iommu_status) {
+                       vop_dev->iommu_status = 1;
+                       rockchip_iovmm_activate(dev_drv->dev);
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_mmu_disable(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (!dev_drv->iommu_enabled || !dev_drv->mmu_dev) {
+               pr_debug("%s: VOP iommu is disabled or not find mmu dev\n",
+                        __func__);
+               return -ENODEV;
+       }
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               if (vop_dev->iommu_status) {
+                       vop_dev->iommu_status = 0;
+                       rockchip_iovmm_deactivate(dev_drv->dev);
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_reg_dump(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int *cbase = (int *)vop_dev->regs;
+       int *regsbak = (int *)vop_dev->regsbak;
+       int i, j, val;
+       char dbg_message[30];
+       char buf[10];
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               pr_info("vop back up reg:\n");
+               memset(dbg_message, 0, sizeof(dbg_message));
+               memset(buf, 0, sizeof(buf));
+               for (i = 0; i <= (0x200 >> 4); i++) {
+                       val = sprintf(dbg_message, "0x%04x: ", i * 16);
+                       for (j = 0; j < 4; j++) {
+                               val = sprintf(buf, "%08x  ",
+                                             *(regsbak + i * 4 + j));
+                               strcat(dbg_message, buf);
+                       }
+                       pr_info("%s\n", dbg_message);
+                       memset(dbg_message, 0, sizeof(dbg_message));
+                       memset(buf, 0, sizeof(buf));
+               }
+
+               pr_info("vop reg:\n");
+               for (i = 0; i <= (0x200 >> 4); i++) {
+                       val = sprintf(dbg_message, "0x%04x: ", i * 16);
+                       for (j = 0; j < 4; j++) {
+                               sprintf(buf, "%08x  ",
+                                       readl_relaxed(cbase + i * 4 + j));
+                               strcat(dbg_message, buf);
+                       }
+                       pr_info("%s\n", dbg_message);
+                       memset(dbg_message, 0, sizeof(dbg_message));
+                       memset(buf, 0, sizeof(buf));
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+#define WIN_EN(id)             \
+static int win##id##_enable(struct vop_device *vop_dev, int en)        \
+{ \
+       spin_lock(&vop_dev->reg_lock);                                  \
+       vop_msk_reg(vop_dev, WIN##id##_CTRL0, V_WIN##id##_EN((u64)en)); \
+       vop_cfg_done(vop_dev);                                          \
+       spin_unlock(&vop_dev->reg_lock);                                \
+       return 0;                                                       \
+}
+
+WIN_EN(0);
+WIN_EN(1);
+
+/*
+ * enable/disable win directly
+ */
+static int vop_win_direct_en(struct rk_lcdc_driver *drv,
+                            int win_id, int en)
+{
+       struct vop_device *vop_dev = to_vop_dev(drv);
+
+       if (win_id == 0)
+               win0_enable(vop_dev, en);
+       else if (win_id == 1)
+               win1_enable(vop_dev, en);
+       else
+               dev_err(vop_dev->dev, "invalid win number:%d\n", win_id);
+       return 0;
+}
+
+#define SET_WIN_ADDR(id) \
+static int set_win##id##_addr(struct vop_device *vop_dev, u32 addr) \
+{                                                      \
+       spin_lock(&vop_dev->reg_lock);                  \
+       vop_writel(vop_dev, WIN##id##_YRGB_MST, addr);  \
+       vop_msk_reg(vop_dev, WIN##id##_CTRL0, V_WIN##id##_EN(1));       \
+       vop_cfg_done(vop_dev);                  \
+       spin_unlock(&vop_dev->reg_lock);                \
+       return 0;                                       \
+}
+
+SET_WIN_ADDR(0);
+SET_WIN_ADDR(1);
+
+static int vop_direct_set_win_addr(struct rk_lcdc_driver *dev_drv,
+                                  int win_id, u32 addr)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (win_id == 0)
+               set_win0_addr(vop_dev, addr);
+       else
+               set_win1_addr(vop_dev, addr);
+
+       return 0;
+}
+
+static void vop_read_reg_default_cfg(struct vop_device *vop_dev)
+{
+       int reg = 0;
+       u32 val = 0;
+       struct rk_screen *screen = vop_dev->driver.cur_screen;
+       u32 h_pw_bp = screen->mode.hsync_len + screen->mode.left_margin;
+       u32 V_pw_bp = screen->mode.vsync_len + screen->mode.upper_margin;
+       u32 st_x, st_y;
+       struct rk_lcdc_win *win0 = vop_dev->driver.win[0];
+
+       spin_lock(&vop_dev->reg_lock);
+       for (reg = 0; reg < vop_dev->len; reg += 4) {
+               val = vop_readl_backup(vop_dev, reg);
+               switch (reg) {
+               case WIN0_ACT_INFO:
+                       win0->area[0].xact = (val & MASK(WIN0_ACT_WIDTH)) + 1;
+                       win0->area[0].yact =
+                               ((val & MASK(WIN0_ACT_HEIGHT)) >> 16) + 1;
+                       break;
+               case WIN0_DSP_INFO:
+                       win0->area[0].xsize = (val & MASK(WIN0_DSP_WIDTH)) + 1;
+                       win0->area[0].ysize =
+                           ((val & MASK(WIN0_DSP_HEIGHT)) >> 16) + 1;
+                       break;
+               case WIN0_DSP_ST:
+                       st_x = val & MASK(WIN0_DSP_XST);
+                       st_y = (val & MASK(WIN0_DSP_YST)) >> 16;
+                       win0->area[0].xpos = st_x - h_pw_bp;
+                       win0->area[0].ypos = st_y - V_pw_bp;
+                       break;
+               case WIN0_CTRL0:
+                       win0->state = val & MASK(WIN0_EN);
+                       win0->area[0].fmt_cfg =
+                                       (val & MASK(WIN0_DATA_FMT)) >> 1;
+                       win0->area[0].format = win0->area[0].fmt_cfg;
+                       break;
+               case WIN0_VIR:
+                       win0->area[0].y_vir_stride =
+                                       val & MASK(WIN0_YRGB_VIR_STRIDE);
+                       win0->area[0].uv_vir_stride =
+                           (val & MASK(WIN0_CBR_VIR_STRIDE)) >> 16;
+                       if (win0->area[0].format == ARGB888)
+                               win0->area[0].xvir = win0->area[0].y_vir_stride;
+                       else if (win0->area[0].format == RGB888)
+                               win0->area[0].xvir =
+                                   win0->area[0].y_vir_stride * 4 / 3;
+                       else if (win0->area[0].format == RGB565)
+                               win0->area[0].xvir =
+                                   2 * win0->area[0].y_vir_stride;
+                       else
+                               win0->area[0].xvir =
+                                   4 * win0->area[0].y_vir_stride;
+                       break;
+               case WIN0_YRGB_MST:
+                       win0->area[0].smem_start = val;
+                       break;
+               case WIN0_CBR_MST:
+                       win0->area[0].cbr_start = val;
+                       break;
+               default:
+                       break;
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+}
+
+static int vop_pre_init(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (vop_dev->pre_init)
+               return 0;
+
+       if (dev_drv->iommu_enabled) {
+               dev_drv->mmu_dev = rk_fb_get_sysmmu_device_by_compatible(
+                                                       dev_drv->mmu_dts_name);
+               if (dev_drv->mmu_dev)
+                       rk_fb_platform_set_sysmmu(
+                               dev_drv->mmu_dev, dev_drv->dev);
+               else
+                       dev_err(dev_drv->dev, "fail get rk iommu device\n");
+       }
+
+       if (!support_uboot_display())
+               rk_disp_pwr_enable(dev_drv);
+
+       vop_clk_enable(vop_dev);
+
+       /* backup reg config at uboot */
+       vop_read_reg_default_cfg(vop_dev);
+
+       /* vop io voltage select-->0: 3.3v; 1: 1.8v */
+       if (vop_dev->pwr18 == 1)
+               vop_grf_writel(vop_dev->grf_base, GRF_IO_VSEL,
+                              V_VOP_IOVOL_SEL(1));
+       else
+               vop_grf_writel(vop_dev->grf_base, GRF_IO_VSEL,
+                              V_VOP_IOVOL_SEL(0));
+
+       vop_msk_reg(vop_dev, SYS_CTRL1, V_SW_AXI_MAX_OUTSTAND_EN(1) |
+                   V_SW_AXI_MAX_OUTSTAND_NUM(31));
+       vop_msk_reg(vop_dev, SYS_CTRL2, V_IMD_AUTO_GATING_EN(0));
+       vop_cfg_done(vop_dev);
+       vop_dev->pre_init = true;
+
+       return 0;
+}
+
+static void vop_deinit(struct vop_device *vop_dev)
+{
+       struct rk_lcdc_driver *dev_drv = &vop_dev->driver;
+
+       vop_standby_enable(vop_dev);
+       vop_irq_disable(vop_dev);
+       vop_mmu_disable(dev_drv);
+       vop_clk_disable(vop_dev);
+       clk_unprepare(vop_dev->dclk);
+       clk_unprepare(vop_dev->aclk);
+       clk_unprepare(vop_dev->hclk);
+       pm_runtime_disable(vop_dev->dev);
+}
+
+static void __maybe_unused
+vop_win_csc_mode(struct vop_device *vop_dev, struct rk_lcdc_win *win,
+                int csc_mode)
+{
+       u64 val;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               if (win->id == 0) {
+                       val = V_WIN0_CSC_MODE(csc_mode);
+                       vop_msk_reg(vop_dev, WIN0_CTRL0, val);
+               } else if (win->id == 1) {
+                       val = V_WIN1_CSC_MODE(csc_mode);
+                       vop_msk_reg(vop_dev, WIN1_CTRL0, val);
+               } else {
+                       dev_err(vop_dev->dev, "%s win%d unsupport csc mode",
+                               __func__, win->id);
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+}
+
+static int vop_clr_key_cfg(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win;
+       int i;
+
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               win = dev_drv->win[i];
+               switch (i) {
+               case 0:
+                       vop_writel(vop_dev, WIN0_COLOR_KEY, win->color_key_val);
+                       break;
+               case 1:
+                       vop_writel(vop_dev, WIN1_COLOR_KEY, win->color_key_val);
+                       break;
+               default:
+                       pr_info("%s:un support win num:%d\n",
+                               __func__, i);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int vop_alpha_cfg(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win = dev_drv->win[win_id];
+       u64 val;
+       int ppixel_alpha = 0;
+       int alpha_en = win->alpha_en;
+       int i;
+
+       if (!alpha_en) {
+               if (win_id == 0) {
+                       val = V_WIN0_ALPHA_EN(0);
+                       vop_msk_reg(vop_dev, WIN0_ALPHA_CTRL, val);
+               } else {
+                       val = V_WIN1_ALPHA_EN(0);
+                       vop_msk_reg(vop_dev, WIN1_ALPHA_CTRL, val);
+               }
+               return 0;
+       }
+
+       ppixel_alpha = ((win->area[0].format == ARGB888) ||
+                       (win->area[0].format == ABGR888)) ? 1 : 0;
+
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               if (!dev_drv->win[i]->state)
+                       continue;
+               if (win->z_order > dev_drv->win[i]->z_order)
+                       break;
+       }
+
+       /*
+        * The bottom layer not support ppixel_alpha mode.
+        */
+       if (i == dev_drv->lcdc_win_num) {
+               ppixel_alpha = 0;
+               alpha_en = 0;
+       }
+
+       if (win_id == 0) {
+               val = V_WIN0_ALPHA_EN(alpha_en) |
+                       V_WIN0_ALPHA_MODE(ppixel_alpha) |
+                       V_WIN0_ALPHA_PRE_MUL(ppixel_alpha) |
+                       V_WIN0_ALPHA_SAT_MODE(0);
+               vop_msk_reg(vop_dev, WIN0_ALPHA_CTRL, val);
+       } else if (win_id == 1) {
+               val = V_WIN1_ALPHA_EN(alpha_en) |
+                       V_WIN1_ALPHA_MODE(ppixel_alpha) |
+                       V_WIN1_ALPHA_PRE_MUL(ppixel_alpha) |
+                       V_WIN1_ALPHA_SAT_MODE(0);
+               vop_msk_reg(vop_dev, WIN1_ALPHA_CTRL, val);
+       } else {
+               dev_err(vop_dev->dev, "%s: invalid win id=%d or unsupport\n",
+                       __func__, win_id);
+       }
+
+       return 0;
+}
+
+static int vop_axi_gather_cfg(struct vop_device *vop_dev,
+                             struct rk_lcdc_win *win)
+{
+       u64 val;
+       u16 yrgb_gather_num = 3;
+       u16 cbcr_gather_num = 1;
+
+       switch (win->area[0].format) {
+       case ARGB888:
+       case XBGR888:
+       case ABGR888:
+               yrgb_gather_num = 3;
+               break;
+       case RGB888:
+       case RGB565:
+               yrgb_gather_num = 2;
+               break;
+       case YUV444:
+       case YUV422:
+       case YUV420:
+       case YUV420_A:
+       case YUV422_A:
+       case YUV444_A:
+       case YUV420_NV21:
+               yrgb_gather_num = 1;
+               cbcr_gather_num = 2;
+               break;
+       default:
+               dev_err(vop_dev->driver.dev, "%s:un supported format[%d]\n",
+                       __func__, win->area[0].format);
+               return -EINVAL;
+       }
+
+       if (win->id == 0) {
+               val = V_WIN0_YRGB_AXI_GATHER_EN(1) |
+                       V_WIN0_CBR_AXI_GATHER_EN(1) |
+                       V_WIN0_YRGB_AXI_GATHER_NUM(yrgb_gather_num) |
+                       V_WIN0_CBR_AXI_GATHER_NUM(cbcr_gather_num);
+               vop_msk_reg(vop_dev, WIN0_CTRL1, val);
+       } else if (win->id == 1) {
+               val = V_WIN1_AXI_GATHER_EN(1) |
+                       V_WIN1_AXI_GATHER_NUM(yrgb_gather_num);
+               vop_msk_reg(vop_dev, WIN1_CTRL1, val);
+       }
+       return 0;
+}
+
+static int vop_win0_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win = dev_drv->win[win_id];
+       u64 val;
+
+       if (win->state == 1) {
+               vop_axi_gather_cfg(vop_dev, win);
+               val = V_WIN0_EN(win->state) |
+                       V_WIN0_DATA_FMT(win->area[0].fmt_cfg) |
+                       V_WIN0_RB_SWAP(win->area[0].swap_rb) |
+                       V_WIN0_UV_SWAP(win->area[0].swap_uv);
+               if (dev_drv->cur_screen->mode.vmode & FB_VMODE_INTERLACED)
+                       val |= V_WIN0_INTERLACE_READ(1);
+               vop_msk_reg(vop_dev, WIN0_CTRL0, val);
+
+               val = V_WIN0_YRGB_VIR_STRIDE(win->area[0].y_vir_stride) |
+                   V_WIN0_CBR_VIR_STRIDE(win->area[0].uv_vir_stride);
+               vop_writel(vop_dev, WIN0_VIR, val);
+
+               val = V_WIN0_DSP_WIDTH(win->area[0].xsize - 1) |
+                   V_WIN0_DSP_HEIGHT(win->area[0].ysize - 1);
+               vop_writel(vop_dev, WIN0_DSP_INFO, val);
+
+               val = V_WIN0_DSP_XST(win->area[0].dsp_stx) |
+                   V_WIN0_DSP_YST(win->area[0].dsp_sty);
+               vop_writel(vop_dev, WIN0_DSP_ST, val);
+
+               /* only win0 support scale and yuv */
+               val = V_WIN0_ACT_WIDTH(win->area[0].xact - 1) |
+                       V_WIN0_ACT_HEIGHT(win->area[0].yact - 1);
+               vop_writel(vop_dev, WIN0_ACT_INFO, val);
+
+               val = V_WIN0_HS_FACTOR_YRGB(win->scale_yrgb_x) |
+                       V_WIN0_VS_FACTOR_YRGB(win->scale_yrgb_y);
+               vop_writel(vop_dev, WIN0_SCL_FACTOR_YRGB, val);
+
+               val = V_WIN0_HS_FACTOR_CBR(win->scale_cbcr_x) |
+                       V_WIN0_VS_FACTOR_CBR(win->scale_cbcr_y);
+               vop_writel(vop_dev, WIN0_SCL_FACTOR_CBR, val);
+
+               if (win->area[0].y_addr > 0)
+                       vop_writel(vop_dev, WIN0_YRGB_MST, win->area[0].y_addr);
+               if (win->area[0].uv_addr > 0)
+                       vop_writel(vop_dev, WIN0_CBR_MST, win->area[0].uv_addr);
+
+               vop_alpha_cfg(dev_drv, win_id);
+       } else {
+               val = V_WIN0_EN(win->state);
+               vop_msk_reg(vop_dev, WIN0_CTRL0, val);
+       }
+
+       return 0;
+}
+
+static int vop_win1_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win = dev_drv->win[win_id];
+       u64 val;
+
+       if (win->state == 1) {
+               vop_axi_gather_cfg(vop_dev, win);
+               val = V_WIN1_EN(win->state) |
+                       V_WIN1_DATA_FMT(win->area[0].fmt_cfg) |
+                       V_WIN1_RB_SWAP(win->area[0].swap_rb);
+               if (dev_drv->cur_screen->mode.vmode & FB_VMODE_INTERLACED)
+                       val |= V_WIN1_INTERLACE_READ(1);
+               vop_msk_reg(vop_dev, WIN1_CTRL0, val);
+
+               val = V_WIN1_VIR_STRIDE(win->area[0].y_vir_stride);
+               vop_writel(vop_dev, WIN1_VIR, val);
+
+               val = V_WIN1_DSP_WIDTH(win->area[0].xsize - 1) |
+                   V_WIN1_DSP_HEIGHT(win->area[0].ysize - 1);
+               vop_writel(vop_dev, WIN1_DSP_INFO, val);
+
+               val = V_WIN1_DSP_XST(win->area[0].dsp_stx) |
+                   V_WIN1_DSP_YST(win->area[0].dsp_sty);
+               vop_writel(vop_dev, WIN1_DSP_ST, val);
+
+               if (win->area[0].y_addr > 0)
+                       vop_writel(vop_dev, WIN1_YRGB_MST, win->area[0].y_addr);
+
+               vop_alpha_cfg(dev_drv, win_id);
+       } else {
+               val = V_WIN1_EN(win->state);
+               vop_msk_reg(vop_dev, WIN1_CTRL0, val);
+       }
+
+       return 0;
+}
+
+static int vop_hwc_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win = dev_drv->win[win_id];
+       unsigned int hwc_size = 0;
+       u64 val;
+
+       if (win->state == 1) {
+               vop_axi_gather_cfg(vop_dev, win);
+
+               if ((win->area[0].xsize == 32) && (win->area[0].ysize == 32))
+                       hwc_size = 0;
+               else if ((win->area[0].xsize == 64) &&
+                        (win->area[0].ysize == 64))
+                       hwc_size = 1;
+               else
+                       dev_err(vop_dev->dev, "unsupported hwc size[%dx%d]!\n",
+                               win->area[0].xsize, win->area[0].ysize);
+
+               val = V_HWC_EN(1) | V_HWC_SIZE(hwc_size);
+               vop_msk_reg(vop_dev, HWC_CTRL0, val);
+
+               val = V_HWC_DSP_XST(win->area[0].dsp_stx) |
+                   V_HWC_DSP_YST(win->area[0].dsp_sty);
+               vop_msk_reg(vop_dev, HWC_DSP_ST, val);
+
+               if (win->area[0].y_addr > 0)
+                       vop_writel(vop_dev, HWC_MST, win->area[0].y_addr);
+       } else {
+               val = V_HWC_EN(win->state);
+               vop_msk_reg(vop_dev, HWC_CTRL0, val);
+       }
+
+       return 0;
+}
+
+static int vop_layer_update_regs(struct vop_device *vop_dev,
+                                struct rk_lcdc_win *win)
+{
+       struct rk_lcdc_driver *dev_drv = &vop_dev->driver;
+
+       vop_msk_reg(vop_dev, SYS_CTRL2,
+                   V_IMD_VOP_STANDBY_EN(vop_dev->standby));
+       if (win->id == 0)
+               vop_win0_reg_update(dev_drv, win->id);
+       else if (win->id == 1)
+               vop_win1_reg_update(dev_drv, win->id);
+       else if (win->id == 2)
+               vop_hwc_reg_update(dev_drv, win->id);
+       vop_cfg_done(vop_dev);
+
+       DBG(2, "%s for vop%d\n", __func__, vop_dev->id);
+       return 0;
+}
+
+static int vop_set_hwc_lut(struct rk_lcdc_driver *dev_drv,
+                          int *hwc_lut, int mode)
+{
+       int i = 0;
+       int __iomem *c;
+       int v;
+       int len = 256 * sizeof(u32);
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (!dev_drv->hwc_lut)
+               dev_drv->hwc_lut = devm_kzalloc(vop_dev->dev, len, GFP_KERNEL);
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_msk_reg(vop_dev, HWC_CTRL0, V_HWC_LUT_EN(0));
+               vop_cfg_done(vop_dev);
+               mdelay(25);
+               for (i = 0; i < 256; i++) {
+                       if (mode == 1)
+                               dev_drv->hwc_lut[i] = hwc_lut[i];
+
+                       v = dev_drv->hwc_lut[i];
+                       c = vop_dev->hwc_lut_addr_base + i;
+                       writel_relaxed(v, c);
+               }
+               vop_msk_reg(vop_dev, HWC_CTRL0, V_HWC_LUT_EN(1));
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_set_lut(struct rk_lcdc_driver *dev_drv, int *dsp_lut)
+{
+       int i = 0;
+       int __iomem *c;
+       int v;
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (!dsp_lut)
+               return 0;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_msk_reg(vop_dev, DSP_CTRL2, V_DSP_LUT_EN(0));
+               vop_cfg_done(vop_dev);
+               mdelay(25);
+               for (i = 0; i < 256; i++) {
+                       v = dsp_lut[i];
+                       c = vop_dev->dsp_lut_addr_base + i;
+                       writel_relaxed(v, c);
+               }
+               vop_msk_reg(vop_dev, DSP_CTRL2, V_DSP_LUT_EN(1));
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_set_dclk(struct rk_lcdc_driver *dev_drv, int reset_rate)
+{
+       int ret = 0, fps = 0;
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+
+       if (reset_rate)
+               ret = clk_set_rate(vop_dev->dclk, screen->mode.pixclock);
+       if (ret)
+               dev_err(dev_drv->dev, "set lcdc%d dclk[%d] failed\n",
+                       vop_dev->id, screen->mode.pixclock);
+       vop_dev->pixclock =
+           div_u64(1000000000000llu, clk_get_rate(vop_dev->dclk));
+       vop_dev->driver.pixclock = vop_dev->pixclock;
+
+       fps = rk_fb_calc_fps(screen, vop_dev->pixclock);
+       screen->ft = 1000 / fps;
+       dev_info(vop_dev->dev, "%s: dclk:%lu>>fps:%d ",
+                vop_dev->driver.name, clk_get_rate(vop_dev->dclk), fps);
+       return 0;
+}
+
+static int vop_config_timing(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_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;
+       u64 val;
+       u16 h_total, v_total;
+       u16 vact_end_f1, vact_st_f1, vs_end_f1, vs_st_f1;
+
+       /* config timing reg valid immediately or after frame start */
+       if (screen->mode.vmode & FB_VMODE_INTERLACED) /* after frame start */
+               vop_msk_reg(vop_dev, SYS_CTRL2, V_IMD_DSP_TIMING_IMD(1));
+       else /* timing reg valid immediately */
+               vop_msk_reg(vop_dev, SYS_CTRL2, V_IMD_DSP_TIMING_IMD(0));
+
+       h_total = hsync_len + left_margin + x_res + right_margin;
+       v_total = vsync_len + upper_margin + y_res + lower_margin;
+
+       val = V_DSP_HS_END(hsync_len) | V_DSP_HTOTAL(h_total);
+       vop_msk_reg(vop_dev, DSP_HTOTAL_HS_END, val);
+
+       val = V_DSP_HACT_END(hsync_len + left_margin + x_res) |
+           V_DSP_HACT_ST(hsync_len + left_margin);
+       vop_msk_reg(vop_dev, DSP_HACT_ST_END, val);
+
+       if (screen->mode.vmode & FB_VMODE_INTERLACED) {
+               /* First Field Timing */
+               val = V_DSP_VS_END(vsync_len) |
+                   V_DSP_VTOTAL(2 * (vsync_len + upper_margin +
+                                     lower_margin) + y_res + 1);
+               vop_msk_reg(vop_dev, DSP_VTOTAL_VS_END, val);
+
+               val = V_DSP_VACT_END(vsync_len + upper_margin + y_res / 2) |
+                   V_DSP_VACT_ST(vsync_len + upper_margin);
+               vop_msk_reg(vop_dev, DSP_VACT_ST_END, val);
+
+               /* Second Field Timing */
+               vs_st_f1 = vsync_len + upper_margin + y_res / 2 + lower_margin;
+               vs_end_f1 = 2 * vsync_len + upper_margin + y_res / 2 +
+                   lower_margin;
+               val = V_DSP_VS_ST_F1(vs_st_f1) | V_DSP_VS_END_F1(vs_end_f1);
+               vop_msk_reg(vop_dev, DSP_VS_ST_END_F1, val);
+
+               vact_end_f1 = 2 * (vsync_len + upper_margin) + y_res +
+                   lower_margin + 1;
+               vact_st_f1 = 2 * (vsync_len + upper_margin) + y_res / 2 +
+                   lower_margin + 1;
+               val = V_DSP_VACT_END_F1(vact_end_f1) |
+                       V_DSP_VACT_ST_F1(vact_st_f1);
+               vop_msk_reg(vop_dev, DSP_VACT_ST_END_F1, val);
+
+               val = V_DSP_LINE_FLAG0_NUM(lower_margin ?
+                                          vact_end_f1 : vact_end_f1 - 1);
+
+               val |= V_DSP_LINE_FLAG1_NUM(lower_margin ?
+                                           vact_end_f1 : vact_end_f1 - 1);
+               vop_msk_reg(vop_dev, LINE_FLAG, val);
+       } else {
+               val = V_DSP_VS_END(vsync_len) | V_DSP_VTOTAL(v_total);
+               vop_msk_reg(vop_dev, DSP_VTOTAL_VS_END, val);
+
+               val = V_DSP_VACT_END(vsync_len + upper_margin + y_res) |
+                   V_DSP_VACT_ST(vsync_len + upper_margin);
+               vop_msk_reg(vop_dev, DSP_VACT_ST_END, val);
+
+               val = V_DSP_LINE_FLAG0_NUM(vsync_len + upper_margin + y_res) |
+                       V_DSP_LINE_FLAG1_NUM(vsync_len + upper_margin + y_res);
+               vop_msk_reg(vop_dev, LINE_FLAG, val);
+       }
+
+       return 0;
+}
+
+static int vop_config_source(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+       u64 val = 0;
+
+       switch (screen->type) {
+       case SCREEN_RGB:
+               vop_grf_writel(vop_dev->grf_base, GRF_SOC_CON5,
+                              V_RGB_VOP_SEL(dev_drv->id));
+               val = V_RGB_DCLK_EN(1) | V_RGB_DCLK_POL(screen->pin_dclk) |
+                       V_RGB_HSYNC_POL(screen->pin_hsync) |
+                       V_RGB_VSYNC_POL(screen->pin_vsync) |
+                       V_RGB_DEN_POL(screen->pin_den);
+               break;
+       case SCREEN_HDMI:
+               vop_grf_writel(vop_dev->grf_base, GRF_SOC_CON0,
+                              V_HDMI_VOP_SEL(dev_drv->id));
+               val = V_HDMI_DCLK_EN(1) | V_HDMI_DCLK_POL(screen->pin_dclk) |
+                       V_HDMI_HSYNC_POL(screen->pin_hsync) |
+                       V_HDMI_VSYNC_POL(screen->pin_vsync) |
+                       V_HDMI_DEN_POL(screen->pin_den);
+               break;
+       case SCREEN_LVDS:
+               vop_grf_writel(vop_dev->grf_base, GRF_SOC_CON0,
+                              V_LVDS_VOP_SEL(dev_drv->id));
+               val = V_LVDS_DCLK_EN(1) | V_LVDS_DCLK_POL(screen->pin_dclk) |
+                       V_LVDS_HSYNC_POL(screen->pin_hsync) |
+                       V_LVDS_VSYNC_POL(screen->pin_vsync) |
+                       V_LVDS_DEN_POL(screen->pin_den);
+               break;
+       case SCREEN_MIPI:
+               vop_grf_writel(vop_dev->grf_base, GRF_SOC_CON0,
+                              V_DSI0_VOP_SEL(dev_drv->id));
+               val = V_MIPI_DCLK_EN(1) | V_MIPI_DCLK_POL(screen->pin_dclk) |
+                       V_MIPI_HSYNC_POL(screen->pin_hsync) |
+                       V_MIPI_VSYNC_POL(screen->pin_vsync) |
+                       V_MIPI_DEN_POL(screen->pin_den);
+               break;
+       default:
+               dev_err(vop_dev->dev, "un supported interface[%d]!\n",
+                       screen->type);
+               break;
+       }
+
+       val |= V_SW_CORE_CLK_SEL(!!screen->pixelrepeat);
+       if (screen->mode.vmode & FB_VMODE_INTERLACED)
+               val |= V_SW_HDMI_CLK_I_SEL(1);
+       else
+               val |= V_SW_HDMI_CLK_I_SEL(0);
+       vop_msk_reg(vop_dev, DSP_CTRL0, val);
+
+       return 0;
+}
+
+static int vop_config_interface(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+       u64 val = 0;
+
+       /* FRC dither down init */
+       if (screen->face != OUT_P888) {
+               vop_writel(vop_dev, FRC_LOWER01_0, 0x12844821);
+               vop_writel(vop_dev, FRC_LOWER01_1, 0x21488412);
+               vop_writel(vop_dev, FRC_LOWER10_0, 0xa55a9696);
+               vop_writel(vop_dev, FRC_LOWER10_1, 0x5aa56969);
+               vop_writel(vop_dev, FRC_LOWER11_0, 0xdeb77deb);
+               vop_writel(vop_dev, FRC_LOWER11_1, 0xed7bb7de);
+       }
+
+       switch (screen->face) {
+       case OUT_P888:
+               val = V_DSP_OUT_MODE(OUT_P888) | V_DITHER_DOWN(0);
+               break;
+       case OUT_P565:
+               val = V_DSP_OUT_MODE(OUT_P565) | V_DITHER_DOWN(1) |
+                       V_DITHER_DOWN_MODE(DITHER_888_565) |
+                       V_DITHER_DOWN_SEL(DITHER_SEL_FRC);
+               break;
+       case OUT_P666:
+               val = V_DSP_OUT_MODE(OUT_P666) | V_DITHER_DOWN(1) |
+                       V_DITHER_DOWN_MODE(DITHER_888_666) |
+                       V_DITHER_DOWN_SEL(DITHER_SEL_FRC);
+               break;
+       case OUT_D888_P565:
+               val = V_DSP_OUT_MODE(OUT_P888) | V_DITHER_DOWN(1) |
+                       V_DITHER_DOWN_MODE(DITHER_888_565) |
+                       V_DITHER_DOWN_SEL(DITHER_SEL_FRC);
+               break;
+       case OUT_D888_P666:
+               val = V_DSP_OUT_MODE(OUT_P888) | V_DITHER_DOWN(1) |
+                       V_DITHER_DOWN_MODE(DITHER_888_666) |
+                       V_DITHER_DOWN_SEL(DITHER_SEL_FRC);
+               break;
+       default:
+               dev_err(vop_dev->dev, "un supported screen face[%d]!\n",
+                       screen->face);
+               break;
+       }
+
+       if (screen->mode.vmode & FB_VMODE_INTERLACED)
+               val |= V_DSP_INTERLACE(1) | V_INTERLACE_FIELD_POL(0);
+
+       dev_drv->output_color = screen->color_mode;
+       if (screen->color_mode == COLOR_RGB)
+               dev_drv->overlay_mode = VOP_RGB_DOMAIN;
+       else
+               dev_drv->overlay_mode = VOP_YUV_DOMAIN;
+
+       val |= V_SW_OVERLAY_MODE(dev_drv->overlay_mode) |
+               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_BLANK_EN(0) | V_DSP_BLACK_EN(0);
+       vop_msk_reg(vop_dev, DSP_CTRL2, val);
+
+       return 0;
+}
+
+static void vop_config_background(struct rk_lcdc_driver *dev_drv, int rgb)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u64 val;
+       int b = rgb & 0xff;
+       int g = (rgb >> 8) & 0xff;
+       int r = (rgb >> 16) & 0xff;
+
+       val = V_DSP_BG_BLUE(b) | V_DSP_BG_GREEN(g) | V_DSP_BG_RED(r);
+       vop_msk_reg(vop_dev, DSP_BG, val);
+}
+
+static void vop_bcsh_path_sel(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (dev_drv->overlay_mode == VOP_YUV_DOMAIN) {
+               if (dev_drv->output_color == COLOR_YCBCR)       /* bypass */
+                       vop_msk_reg(vop_dev, BCSH_CTRL,
+                                   V_SW_BCSH_Y2R_EN(0) | V_SW_BCSH_R2Y_EN(0));
+               else            /* YUV2RGB */
+                       vop_msk_reg(vop_dev, BCSH_CTRL, V_SW_BCSH_Y2R_EN(1) |
+                                   V_SW_BCSH_Y2R_CSC_MODE(VOP_Y2R_CSC_MPEG) |
+                                   V_SW_BCSH_R2Y_EN(0));
+       } else {
+               /* overlay_mode=VOP_RGB_DOMAIN */
+               /* bypass  --need check,if bcsh close? */
+               if (dev_drv->output_color == COLOR_RGB) {
+                       if (dev_drv->bcsh.enable == 1)
+                               vop_msk_reg(vop_dev, BCSH_CTRL,
+                                           V_SW_BCSH_R2Y_EN(1) |
+                                           V_SW_BCSH_Y2R_EN(1));
+                       else
+                               vop_msk_reg(vop_dev, BCSH_CTRL,
+                                           V_SW_BCSH_R2Y_EN(0) |
+                                           V_SW_BCSH_Y2R_EN(0));
+               } else {
+                       /* RGB2YUV */
+                       vop_msk_reg(vop_dev, BCSH_CTRL,
+                                   V_SW_BCSH_R2Y_EN(1) |
+                                   V_SW_BCSH_R2Y_CSC_MODE(VOP_Y2R_CSC_MPEG) |
+                                   V_SW_BCSH_Y2R_EN(0));
+               }
+       }
+}
+
+static int vop_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact,
+                              u16 *yact, int *format, u32 *dsp_addr,
+                              int *ymirror)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u32 val;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               val = vop_readl(vop_dev, WIN0_ACT_INFO);
+               *xact = (val & MASK(WIN0_ACT_WIDTH)) + 1;
+               *yact = ((val & MASK(WIN0_ACT_HEIGHT)) >> 16) + 1;
+
+               val = vop_readl(vop_dev, WIN0_CTRL0);
+               *format = (val & MASK(WIN0_DATA_FMT)) >> 1;
+               *dsp_addr = vop_readl(vop_dev, WIN0_YRGB_MST);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
+                          int format, u16 xact, u16 yact, u16 xvir,
+                          int ymirror)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int swap = (format == RGB888) ? 1 : 0;
+       u64 val;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               val = V_WIN0_DATA_FMT(format) | V_WIN0_RB_SWAP(swap);
+               vop_msk_reg(vop_dev, WIN0_CTRL0, val);
+
+               vop_msk_reg(vop_dev, WIN0_VIR, V_WIN0_YRGB_VIR_STRIDE(xvir));
+               vop_writel(vop_dev, WIN0_ACT_INFO, V_WIN0_ACT_WIDTH(xact - 1) |
+                          V_WIN0_ACT_HEIGHT(yact - 1));
+
+               vop_writel(vop_dev, WIN0_YRGB_MST, rgb_mst);
+
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static void vop_reg_restore(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int len = FLAG_REG;
+
+       spin_lock(&vop_dev->reg_lock);
+
+       if (likely(vop_dev->clk_on))
+               memcpy(vop_dev->regs, vop_dev->regsbak, len);
+
+       spin_unlock(&vop_dev->reg_lock);
+
+       /* set screen GAMMA lut */
+       if (dev_drv->cur_screen && dev_drv->cur_screen->dsp_lut)
+               vop_set_lut(dev_drv, dev_drv->cur_screen->dsp_lut);
+
+       /* set hwc lut */
+       vop_set_hwc_lut(dev_drv, dev_drv->hwc_lut, 0);
+}
+
+static int vop_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+
+       /*if (!vop_dev->standby && initscreen && (dev_drv->first_frame != 1))*/
+       /*      flush_kthread_worker(&dev_drv->update_regs_worker);*/
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_config_interface(dev_drv);
+               vop_config_source(dev_drv);
+               vop_config_timing(dev_drv);
+               if (dev_drv->overlay_mode == VOP_YUV_DOMAIN)
+                       vop_config_background(dev_drv, 0x801080);
+               else
+                       vop_config_background(dev_drv, 0x000000);
+
+               vop_bcsh_path_sel(dev_drv);
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       vop_set_dclk(dev_drv, 1);
+       if (screen->init)
+               screen->init();
+
+       return 0;
+}
+
+/*
+ * enable or disable layer according to win id
+ * @open: 1 enable; 0 disable
+ */
+static void vop_layer_enable(struct vop_device *vop_dev,
+                            unsigned int win_id, bool open)
+{
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on) &&
+           vop_dev->driver.win[win_id]->state != open) {
+               if (open) {
+                       if (!vop_dev->atv_layer_cnt) {
+                               dev_info(vop_dev->dev,
+                                        "wakeup from standby!\n");
+                               vop_dev->standby = 0;
+                       }
+                       vop_dev->atv_layer_cnt |= (1 << win_id);
+               } else {
+                       if (vop_dev->atv_layer_cnt & (1 << win_id))
+                               vop_dev->atv_layer_cnt &= ~(1 << win_id);
+               }
+               vop_dev->driver.win[win_id]->state = open;
+               if (!open) {
+                       vop_layer_update_regs(vop_dev,
+                                             vop_dev->driver.win[win_id]);
+                       vop_cfg_done(vop_dev);
+               }
+               /* if no layer used,disable lcdc */
+               if (!vop_dev->atv_layer_cnt) {
+                       dev_info(vop_dev->dev,
+                                "no layer is used,go to standby!\n");
+                       vop_dev->standby = 1;
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+}
+
+static int vop_open(struct rk_lcdc_driver *dev_drv, int win_id,
+                   bool open)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       /* enable clk,when first layer open */
+       if ((open) && (!vop_dev->atv_layer_cnt)) {
+               /* rockchip_set_system_status(sys_status); */
+               vop_pre_init(dev_drv);
+               vop_clk_enable(vop_dev);
+               vop_irq_enable(vop_dev);
+
+               if (support_uboot_display() && (vop_dev->prop == PRMRY)) {
+                       vop_set_dclk(dev_drv, 0);
+               } else {
+                       vop_load_screen(dev_drv, 1);
+                       if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
+                               dev_drv->trsm_ops->enable();
+               }
+               if (dev_drv->bcsh.enable)
+                       vop_set_bcsh(dev_drv, 1);
+
+               /* set screen GAMMA lut */
+               if (dev_drv->cur_screen && dev_drv->cur_screen->dsp_lut)
+                       vop_set_lut(dev_drv, dev_drv->cur_screen->dsp_lut);
+       }
+
+       if (win_id < ARRAY_SIZE(vop_win))
+               vop_layer_enable(vop_dev, win_id, open);
+       else
+               dev_err(vop_dev->dev, "invalid win id:%d\n", win_id);
+
+       dev_drv->first_frame = 0;
+       return 0;
+}
+
+static int vop_pan_display(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_lcdc_win *win = NULL;
+       struct rk_screen *screen = dev_drv->cur_screen;
+
+       if (!screen) {
+               dev_err(dev_drv->dev, "screen is null!\n");
+               return -ENOENT;
+       }
+
+       if (win_id >= dev_drv->lcdc_win_num) {
+               dev_err(dev_drv->dev, "invalid win id:%d!\n", win_id);
+               return -EINVAL;
+       }
+
+       win = dev_drv->win[win_id];
+       win->area[0].y_addr = win->area[0].smem_start + win->area[0].y_offset;
+       /* only win0 support yuv format */
+       if (win_id == 0)
+               win->area[0].uv_addr =
+                       win->area[0].cbr_start + win->area[0].c_offset;
+       else
+               win->area[0].uv_addr = 0;
+
+       DBG(2, "lcdc[%d]:win[%d]>>:y_addr:0x%x>>uv_addr:0x%x",
+           vop_dev->id, win->id, win->area[0].y_addr, win->area[0].uv_addr);
+       DBG(2, ">>y_offset:0x%x>>c_offset=0x%x\n",
+           win->area[0].y_offset, win->area[0].c_offset);
+       return 0;
+}
+
+static int win_0_1_set_par(struct vop_device *vop_dev,
+                          struct rk_screen *screen, struct rk_lcdc_win *win)
+{
+       char fmt[9] = "NULL";
+
+       win->area[0].dsp_stx = win->area[0].xpos + screen->mode.left_margin +
+                               screen->mode.hsync_len;
+       if (screen->mode.vmode & FB_VMODE_INTERLACED) {
+               win->area[0].ysize /= 2;
+               win->area[0].dsp_sty = win->area[0].ypos / 2 +
+                       screen->mode.upper_margin + screen->mode.vsync_len;
+       } else {
+               win->area[0].dsp_sty = win->area[0].ypos +
+                       screen->mode.upper_margin + screen->mode.vsync_len;
+       }
+
+       win->scale_yrgb_x = CALSCALE(win->area[0].xact, win->area[0].xsize);
+       win->scale_yrgb_y = CALSCALE(win->area[0].yact, win->area[0].ysize);
+
+       switch (win->area[0].format) {
+       case ARGB888:
+               win->area[0].fmt_cfg = VOP_FORMAT_ARGB888;
+               win->area[0].swap_rb = 0;
+               break;
+       case XBGR888:
+       case ABGR888:
+               win->area[0].fmt_cfg = VOP_FORMAT_ARGB888;
+               win->area[0].swap_rb = 1;
+               break;
+       case RGB888:
+               win->area[0].fmt_cfg = VOP_FORMAT_RGB888;
+               win->area[0].swap_rb = 0;
+               break;
+       case RGB565:
+               win->area[0].fmt_cfg = VOP_FORMAT_RGB565;
+               win->area[0].swap_rb = 0;
+               break;
+       case YUV422:
+               if (win->id == 0) {
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR422;
+                       win->area[0].swap_rb = 0;
+                       win->area[0].swap_uv = 0;
+                       win->scale_cbcr_x = CALSCALE(win->area[0].xact / 2,
+                                                    win->area[0].xsize);
+                       win->scale_cbcr_y = CALSCALE(win->area[0].yact,
+                                                    win->area[0].ysize);
+               } else {
+                       dev_err(vop_dev->dev, "%s:win%d unsupport YUV format\n",
+                               __func__, win->id);
+               }
+               break;
+       case YUV420:
+               if (win->id == 0) {
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR420;
+                       win->area[0].swap_rb = 0;
+                       win->area[0].swap_uv = 0;
+                       win->scale_cbcr_x = CALSCALE(win->area[0].xact / 2,
+                                                    win->area[0].xsize);
+                       win->scale_cbcr_y = CALSCALE(win->area[0].yact / 2,
+                                                    win->area[0].ysize);
+               } else {
+                       dev_err(vop_dev->dev, "%s:win%d unsupport YUV format\n",
+                               __func__, win->id);
+               }
+
+               break;
+       case YUV420_NV21:
+               if (win->id == 0) {
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR420;
+                       win->area[0].swap_rb = 0;
+                       win->area[0].swap_uv = 1;
+                       win->scale_cbcr_x = CALSCALE(win->area[0].xact / 2,
+                                                    win->area[0].xsize);
+                       win->scale_cbcr_y = CALSCALE(win->area[0].yact / 2,
+                                                    win->area[0].ysize);
+               } else {
+                       dev_err(vop_dev->dev, "%s:win%d unsupport YUV format\n",
+                               __func__, win->id);
+               }
+               break;
+       case YUV444:
+               if (win->id == 0) {
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR444;
+                       win->area[0].swap_rb = 0;
+                       win->area[0].swap_uv = 0;
+                       win->scale_cbcr_x =
+                               CALSCALE(win->area[0].xact, win->area[0].xsize);
+                       win->scale_cbcr_y =
+                               CALSCALE(win->area[0].yact, win->area[0].ysize);
+               } else {
+                       dev_err(vop_dev->dev, "%s:win%d unsupport YUV format\n",
+                               __func__, win->id);
+               }
+               break;
+       default:
+               dev_err(vop_dev->dev, "%s:unsupport format[%d]!\n",
+                       __func__, win->area[0].format);
+               break;
+       }
+
+       DBG(1, "lcdc[%d]:win[%d]\n>>format:%s>>>xact:%d>>yact:%d>>xsize:%d",
+           vop_dev->id, win->id, get_format_string(win->area[0].format, fmt),
+           win->area[0].xact, win->area[0].yact, win->area[0].xsize);
+       DBG(1, ">>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n",
+           win->area[0].ysize, win->area[0].xvir, win->area[0].yvir,
+           win->area[0].xpos, win->area[0].ypos);
+
+       return 0;
+}
+
+static int hwc_set_par(struct vop_device *vop_dev,
+                      struct rk_screen *screen, struct rk_lcdc_win *win)
+{
+       win->area[0].dsp_stx = win->area[0].xpos + screen->mode.left_margin +
+                               screen->mode.hsync_len;
+       win->area[0].dsp_sty = win->area[0].ypos + screen->mode.upper_margin +
+                               screen->mode.vsync_len;
+
+       DBG(1, "lcdc[%d]:hwc>>%s\n>>xsize:%d>>ysize:%d>>xpos:%d>>ypos:%d",
+           vop_dev->id, __func__, win->area[0].xsize, win->area[0].ysize,
+           win->area[0].xpos, win->area[0].ypos);
+       return 0;
+}
+
+static int vop_set_par(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+
+       if (!screen) {
+               dev_err(dev_drv->dev, "screen is null!\n");
+               return -ENOENT;
+       }
+
+       switch (win_id) {
+       case 0:
+               win_0_1_set_par(vop_dev, screen, dev_drv->win[0]);
+               break;
+       case 1:
+               win_0_1_set_par(vop_dev, screen, dev_drv->win[1]);
+               break;
+       case 2:
+               hwc_set_par(vop_dev, screen, dev_drv->win[2]);
+               break;
+       default:
+               dev_err(dev_drv->dev, "%s: unsupported win id:%d\n",
+                       __func__, win_id);
+               break;
+       }
+       return 0;
+}
+
+static int vop_ioctl(struct rk_lcdc_driver *dev_drv, unsigned int cmd,
+                    unsigned long arg, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u32 panel_size[2];
+       void __user *argp = (void __user *)arg;
+       struct color_key_cfg clr_key_cfg;
+
+       switch (cmd) {
+       case RK_FBIOGET_PANEL_SIZE:
+               panel_size[0] = vop_dev->screen->mode.xres;
+               panel_size[1] = vop_dev->screen->mode.yres;
+               if (copy_to_user(argp, panel_size, 8))
+                       return -EFAULT;
+               break;
+       case RK_FBIOPUT_COLOR_KEY_CFG:
+               if (copy_from_user(&clr_key_cfg, argp,
+                                  sizeof(struct color_key_cfg)))
+                       return -EFAULT;
+               vop_clr_key_cfg(dev_drv);
+               vop_writel(vop_dev, WIN0_COLOR_KEY,
+                          clr_key_cfg.win0_color_key_cfg);
+               vop_writel(vop_dev, WIN1_COLOR_KEY,
+                          clr_key_cfg.win1_color_key_cfg);
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int vop_get_backlight_device(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct device_node *backlight;
+       struct property *prop;
+       u32 *brightness_levels;
+       u32 length, max, last;
+
+       if (vop_dev->backlight)
+               return 0;
+       backlight = of_parse_phandle(vop_dev->dev->of_node, "backlight", 0);
+       if (backlight) {
+               vop_dev->backlight = of_find_backlight_by_node(backlight);
+               if (!vop_dev->backlight)
+                       dev_info(vop_dev->dev, "No find backlight device\n");
+       } else {
+               dev_info(vop_dev->dev, "No find backlight device node\n");
+       }
+       prop = of_find_property(backlight, "brightness-levels", &length);
+       if (!prop)
+               return -EINVAL;
+       max = length / sizeof(u32);
+       last = max - 1;
+       brightness_levels = kmalloc(256, GFP_KERNEL);
+       if (brightness_levels)
+               return -ENOMEM;
+
+       if (!of_property_read_u32_array(backlight, "brightness-levels",
+                                       brightness_levels, max)) {
+               if (brightness_levels[0] > brightness_levels[last])
+                       dev_drv->cabc_pwm_pol = 1;/*negative*/
+               else
+                       dev_drv->cabc_pwm_pol = 0;/*positive*/
+       } else {
+               dev_info(vop_dev->dev,
+                        "Can not read brightness-levels value\n");
+       }
+
+       kfree(brightness_levels);
+
+       return 0;
+}
+
+static int vop_backlight_close(struct rk_lcdc_driver *dev_drv, int enable)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (dev_drv->suspend_flag)
+               return 0;
+
+       vop_get_backlight_device(dev_drv);
+
+       if (enable) {
+               /* close the backlight */
+               if (vop_dev->backlight) {
+                       vop_dev->backlight->props.power = FB_BLANK_POWERDOWN;
+                       backlight_update_status(vop_dev->backlight);
+               }
+               if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+                       dev_drv->trsm_ops->disable();
+       } else {
+               if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
+                       dev_drv->trsm_ops->enable();
+               msleep(100);
+               /* open the backlight */
+               if (vop_dev->backlight) {
+                       vop_dev->backlight->props.power = FB_BLANK_UNBLANK;
+                       backlight_update_status(vop_dev->backlight);
+               }
+       }
+
+       return 0;
+}
+
+static int vop_early_suspend(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (dev_drv->suspend_flag)
+               return 0;
+
+       dev_drv->suspend_flag = 1;
+       smp_wmb();
+       flush_kthread_worker(&dev_drv->update_regs_worker);
+
+       if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+               dev_drv->trsm_ops->disable();
+
+       vop_standby_enable(vop_dev);
+       vop_mmu_disable(dev_drv);
+       vop_clk_disable(vop_dev);
+       rk_disp_pwr_disable(dev_drv);
+
+       return 0;
+}
+
+static int vop_early_resume(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (!dev_drv->suspend_flag)
+               return 0;
+
+       rk_disp_pwr_enable(dev_drv);
+       vop_clk_enable(vop_dev);
+       vop_reg_restore(dev_drv);
+       vop_standby_disable(vop_dev);
+       vop_mmu_enable(dev_drv);
+       dev_drv->suspend_flag = 0;
+
+       if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
+               dev_drv->trsm_ops->enable();
+
+       return 0;
+}
+
+static int vop_blank(struct rk_lcdc_driver *dev_drv, int win_id, int blank_mode)
+{
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               vop_early_resume(dev_drv);
+               break;
+       case FB_BLANK_NORMAL:
+               vop_early_suspend(dev_drv);
+               break;
+       default:
+               vop_early_suspend(dev_drv);
+               break;
+       }
+
+       dev_info(dev_drv->dev, "blank mode:%d\n", blank_mode);
+
+       return 0;
+}
+
+static int vop_get_win_state(struct rk_lcdc_driver *dev_drv,
+                            int win_id, int area_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u32 area_status = 0, state = 0;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               switch (win_id) {
+               case 0:
+                       area_status =
+                               vop_read_bit(vop_dev, WIN0_CTRL0, V_WIN0_EN(0));
+                       break;
+               case 1:
+                       area_status =
+                               vop_read_bit(vop_dev, WIN1_CTRL0, V_WIN1_EN(0));
+                       break;
+               case 2:
+                       area_status =
+                               vop_read_bit(vop_dev, HWC_CTRL0, V_HWC_EN(0));
+                       break;
+               default:
+                       pr_err("%s: win[%d]area[%d],unsupport!!!\n",
+                              __func__, win_id, area_id);
+                       break;
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       state = (area_status > 0) ? 1 : 0;
+       return state;
+}
+
+static int vop_get_area_num(struct rk_lcdc_driver *dev_drv,
+                           unsigned int *area_support)
+{
+       area_support[0] = 1;
+       area_support[1] = 1;
+
+       return 0;
+}
+
+static int vop_ovl_mgr(struct rk_lcdc_driver *dev_drv, int swap, bool set)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int ovl;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               if (set) {
+                       vop_msk_reg(vop_dev, DSP_CTRL2, V_DSP_WIN0_TOP(swap));
+                       ovl = swap;
+               } else {
+                       ovl =
+                           vop_read_bit(vop_dev, DSP_CTRL2, V_DSP_WIN0_TOP(0));
+               }
+       } else {
+               ovl = -EPERM;
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return ovl;
+}
+
+static char *vop_format_to_string(int format, char *fmt)
+{
+       if (!fmt)
+               return NULL;
+
+       switch (format) {
+       case 0:
+               strcpy(fmt, "ARGB888");
+               break;
+       case 1:
+               strcpy(fmt, "RGB888");
+               break;
+       case 2:
+               strcpy(fmt, "RGB565");
+               break;
+       case 4:
+               strcpy(fmt, "YCbCr420");
+               break;
+       case 5:
+               strcpy(fmt, "YCbCr422");
+               break;
+       case 6:
+               strcpy(fmt, "YCbCr444");
+               break;
+       default:
+               strcpy(fmt, "invalid\n");
+               break;
+       }
+       return fmt;
+}
+
+static ssize_t vop_get_disp_info(struct rk_lcdc_driver *dev_drv,
+                                char *buf, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+       u16 hsync_len = screen->mode.hsync_len;
+       u16 left_margin = screen->mode.left_margin;
+       u16 vsync_len = screen->mode.vsync_len;
+       u16 upper_margin = screen->mode.upper_margin;
+       u32 h_pw_bp = hsync_len + left_margin;
+       u32 v_pw_bp = vsync_len + upper_margin;
+       u32 fmt_id;
+       char format_w0[9] = "NULL";
+       char format_w1[9] = "NULL";
+       char dsp_buf[100];
+       u32 win_ctrl, ovl, vir_info, act_info, dsp_info, dsp_st;
+       u32 y_factor, uv_factor;
+       u8 w0_state, w1_state;
+
+       u32 w0_vir_y, w0_vir_uv, w0_act_x, w0_act_y, w0_dsp_x, w0_dsp_y;
+       u32 w0_st_x = h_pw_bp, w0_st_y = v_pw_bp;
+       u32 w1_vir_y, w1_dsp_x, w1_dsp_y;
+       u32 w1_st_x = h_pw_bp, w1_st_y = v_pw_bp;
+       u32 w0_y_h_fac, w0_y_v_fac, w0_uv_h_fac, w0_uv_v_fac;
+
+       u32 dclk_freq;
+       int size = 0;
+
+       dclk_freq = screen->mode.pixclock;
+       /*vop_reg_dump(dev_drv); */
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               ovl = vop_read_bit(vop_dev, DSP_CTRL2, V_DSP_WIN0_TOP(0));
+               /* WIN0 */
+               win_ctrl = vop_readl(vop_dev, WIN0_CTRL0);
+               w0_state = win_ctrl & MASK(WIN0_EN);
+               fmt_id = (win_ctrl & MASK(WIN0_DATA_FMT)) >> 1;
+               vop_format_to_string(fmt_id, format_w0);
+               vir_info = vop_readl(vop_dev, WIN0_VIR);
+               act_info = vop_readl(vop_dev, WIN0_ACT_INFO);
+               dsp_info = vop_readl(vop_dev, WIN0_DSP_INFO);
+               dsp_st = vop_readl(vop_dev, WIN0_DSP_ST);
+               y_factor = vop_readl(vop_dev, WIN0_SCL_FACTOR_YRGB);
+               uv_factor = vop_readl(vop_dev, WIN0_SCL_FACTOR_CBR);
+               w0_vir_y = vir_info & MASK(WIN0_YRGB_VIR_STRIDE);
+               w0_vir_uv = (vir_info & MASK(WIN0_CBR_VIR_STRIDE)) >> 16;
+               w0_act_x = (act_info & MASK(WIN0_ACT_WIDTH)) + 1;
+               w0_act_y = ((act_info & MASK(WIN0_ACT_HEIGHT)) >> 16) + 1;
+               w0_dsp_x = (dsp_info & MASK(WIN0_DSP_WIDTH)) + 1;
+               w0_dsp_y = ((dsp_info & MASK(WIN0_DSP_HEIGHT)) >> 16) + 1;
+               if (w0_state) {
+                       w0_st_x = dsp_st & MASK(WIN0_DSP_XST);
+                       w0_st_y = (dsp_st & MASK(WIN0_DSP_YST)) >> 16;
+               }
+               w0_y_h_fac = y_factor & MASK(WIN0_HS_FACTOR_YRGB);
+               w0_y_v_fac = (y_factor & MASK(WIN0_VS_FACTOR_YRGB)) >> 16;
+               w0_uv_h_fac = uv_factor & MASK(WIN0_HS_FACTOR_CBR);
+               w0_uv_v_fac = (uv_factor & MASK(WIN0_VS_FACTOR_CBR)) >> 16;
+
+               /* WIN1 */
+               win_ctrl = vop_readl(vop_dev, WIN1_CTRL0);
+               w1_state = win_ctrl & MASK(WIN1_EN);
+               fmt_id = (win_ctrl & MASK(WIN1_DATA_FMT)) >> 1;
+               vop_format_to_string(fmt_id, format_w1);
+               vir_info = vop_readl(vop_dev, WIN1_VIR);
+               dsp_info = vop_readl(vop_dev, WIN1_DSP_INFO);
+               dsp_st = vop_readl(vop_dev, WIN1_DSP_ST);
+               w1_vir_y = vir_info & MASK(WIN1_VIR_STRIDE);
+               w1_dsp_x = (dsp_info & MASK(WIN1_DSP_WIDTH)) + 1;
+               w1_dsp_y = ((dsp_info & MASK(WIN1_DSP_HEIGHT)) >> 16) + 1;
+               if (w1_state) {
+                       w1_st_x = dsp_st & MASK(WIN1_DSP_XST);
+                       w1_st_y = (dsp_st & MASK(WIN1_DSP_YST)) >> 16;
+               }
+       } else {
+               spin_unlock(&vop_dev->reg_lock);
+               return -EPERM;
+       }
+       spin_unlock(&vop_dev->reg_lock);
+       /* win0 */
+       size += snprintf(dsp_buf, 80,
+                "win0:\n  state:%d, fmt:%7s\n  y_vir:%4d, uv_vir:%4d,",
+                w0_state, format_w0, w0_vir_y, w0_vir_uv);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                " x_act  :%5d, y_act  :%5d, dsp_x   :%5d, dsp_y   :%5d\n",
+                w0_act_x, w0_act_y, w0_dsp_x, w0_dsp_y);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                "  x_st :%4d, y_st  :%4d, y_h_fac:%5d, y_v_fac:%5d, ",
+                w0_st_x - h_pw_bp, w0_st_y - v_pw_bp, w0_y_h_fac, w0_y_v_fac);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                "uv_h_fac:%5d, uv_v_fac:%5d\n  y_addr:0x%08x,    uv_addr:0x%08x\n",
+                w0_uv_h_fac, w0_uv_v_fac, vop_readl(vop_dev, WIN0_YRGB_MST),
+                vop_readl(vop_dev, WIN0_CBR_MST));
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       /* win1 */
+       size += snprintf(dsp_buf, 80,
+                "win1:\n  state:%d, fmt:%7s\n  y_vir:%4d,",
+                w1_state, format_w1, w1_vir_y);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                " dsp_x   :%5d, dsp_y   :%5d\n",
+                w1_dsp_x, w1_dsp_y);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                "  x_st :%4d, y_st  :%4d, ",
+                w1_st_x - h_pw_bp, w1_st_y - v_pw_bp);
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       size += snprintf(dsp_buf, 80,
+                "y_addr:0x%08x\n",
+                vop_readl(vop_dev, WIN1_YRGB_MST));
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       /* zorder */
+       size += snprintf(dsp_buf, 80,
+                        ovl ? "win0 on the top of win1\n" :
+                               "win1 on the top of win0\n");
+       strcat(buf, dsp_buf);
+       memset(dsp_buf, 0, sizeof(dsp_buf));
+
+       return size;
+}
+
+static int vop_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps, bool set)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       struct rk_screen *screen = dev_drv->cur_screen;
+       u64 ft = 0;
+       u32 dotclk;
+       int ret;
+       u32 pixclock;
+       u32 x_total, y_total;
+
+       if (set) {
+               if (fps == 0) {
+                       dev_info(dev_drv->dev, "unsupport set fps=0\n");
+                       return 0;
+               }
+               ft = div_u64(1000000000000llu, fps);
+               x_total =
+                   screen->mode.upper_margin + screen->mode.lower_margin +
+                   screen->mode.yres + screen->mode.vsync_len;
+               y_total =
+                   screen->mode.left_margin + screen->mode.right_margin +
+                   screen->mode.xres + screen->mode.hsync_len;
+               dev_drv->pixclock = div_u64(ft, x_total * y_total);
+               dotclk = div_u64(1000000000000llu, dev_drv->pixclock);
+               ret = clk_set_rate(vop_dev->dclk, dotclk);
+       }
+
+       pixclock = div_u64(1000000000000llu, clk_get_rate(vop_dev->dclk));
+       vop_dev->pixclock = pixclock;
+       dev_drv->pixclock = vop_dev->pixclock;
+       fps = rk_fb_calc_fps(screen, pixclock);
+       screen->ft = 1000 / fps;        /*one frame time in ms */
+
+       if (set)
+               dev_info(dev_drv->dev, "%s:dclk:%lu,fps:%d\n", __func__,
+                        clk_get_rate(vop_dev->dclk), fps);
+
+       return fps;
+}
+
+static int vop_fb_win_remap(struct rk_lcdc_driver *dev_drv, u16 order)
+{
+       mutex_lock(&dev_drv->fb_win_id_mutex);
+       if (order == FB_DEFAULT_ORDER)
+               order = FB0_WIN0_FB1_WIN1_FB2_WIN2_FB3_WIN3_FB4_HWC;
+       dev_drv->fb4_win_id = order / 10000;
+       dev_drv->fb3_win_id = (order / 1000) % 10;
+       dev_drv->fb2_win_id = (order / 100) % 10;
+       dev_drv->fb1_win_id = (order / 10) % 10;
+       dev_drv->fb0_win_id = order % 10;
+       mutex_unlock(&dev_drv->fb_win_id_mutex);
+
+       return 0;
+}
+
+static int vop_get_win_id(struct rk_lcdc_driver *dev_drv, const char *id)
+{
+       int win_id = 0;
+
+       mutex_lock(&dev_drv->fb_win_id_mutex);
+       if (!strcmp(id, "fb0") || !strcmp(id, "fb5"))
+               win_id = dev_drv->fb0_win_id;
+       else if (!strcmp(id, "fb1") || !strcmp(id, "fb6"))
+               win_id = dev_drv->fb1_win_id;
+       else if (!strcmp(id, "fb2") || !strcmp(id, "fb7"))
+               win_id = dev_drv->fb2_win_id;
+       else if (!strcmp(id, "fb3") || !strcmp(id, "fb8"))
+               win_id = dev_drv->fb3_win_id;
+       else if (!strcmp(id, "fb4") || !strcmp(id, "fb9"))
+               win_id = dev_drv->fb4_win_id;
+       mutex_unlock(&dev_drv->fb_win_id_mutex);
+
+       return win_id;
+}
+
+static int vop_config_done(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int i;
+       struct rk_lcdc_win *win = NULL;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+                       win = dev_drv->win[i];
+                       vop_layer_update_regs(vop_dev, win);
+               }
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_dpi_open(struct rk_lcdc_driver *dev_drv, bool open)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_msk_reg(vop_dev, SYS_CTRL0, V_DIRECT_PATH_EN(open));
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_dpi_win_sel(struct rk_lcdc_driver *dev_drv, int win_id)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               vop_msk_reg(vop_dev, SYS_CTRL0,
+                           V_DIRECT_PATH_LAYER_SEL(win_id));
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+       return 0;
+}
+
+static int vop_dpi_status(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       int status;
+
+       spin_lock(&vop_dev->reg_lock);
+
+       if (likely(vop_dev->clk_on))
+               status = vop_read_bit(vop_dev, SYS_CTRL0, V_DIRECT_PATH_EN(0));
+
+       spin_unlock(&vop_dev->reg_lock);
+
+       return status;
+}
+
+static int vop_set_irq_to_cpu(struct rk_lcdc_driver *dev_drv, int enable)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (enable)
+               enable_irq(vop_dev->irq);
+       else
+               disable_irq(vop_dev->irq);
+       return 0;
+}
+
+static int vop_poll_vblank(struct rk_lcdc_driver *dev_drv)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u32 int_reg;
+       int ret;
+
+       if (vop_dev->clk_on && (!dev_drv->suspend_flag)) {
+               int_reg = vop_readl(vop_dev, INTR_STATUS);
+               if (int_reg & INTR_LINE_FLAG0) {
+                       vop_dev->driver.frame_time.last_framedone_t =
+                           vop_dev->driver.frame_time.framedone_t;
+                       vop_dev->driver.frame_time.framedone_t = cpu_clock(0);
+                       vop_mask_writel(vop_dev, INTR_CLEAR, INTR_LINE_FLAG0,
+                                       INTR_LINE_FLAG0);
+                       ret = RK_LF_STATUS_FC;
+               } else {
+                       ret = RK_LF_STATUS_FR;
+               }
+       } else {
+               ret = RK_LF_STATUS_NC;
+       }
+
+       return ret;
+}
+
+static int vop_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
+                           unsigned int dsp_addr[][4])
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               dsp_addr[0][0] = vop_readl(vop_dev, WIN0_YRGB_MST);
+               dsp_addr[1][0] = vop_readl(vop_dev, WIN1_YRGB_MST);
+               dsp_addr[2][0] = vop_readl(vop_dev, HWC_MST);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+       return 0;
+}
+
+/*
+ * a:[-30~0]:
+ *     sin_hue = sin(a)*256 +0x100;
+ *     cos_hue = cos(a)*256;
+ * a:[0~30]
+ *     sin_hue = sin(a)*256;
+ *     cos_hue = cos(a)*256;
+ */
+static int vop_get_bcsh_hue(struct rk_lcdc_driver *dev_drv, bcsh_hue_mode mode)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u32 val = 0;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               val = vop_readl(vop_dev, BCSH_H);
+               switch (mode) {
+               case H_SIN:
+                       val &= MASK(SIN_HUE);
+                       val <<= 1;
+                       break;
+               case H_COS:
+                       val &= MASK(COS_HUE);
+                       val >>= 8;
+                       val <<= 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return val;
+}
+
+static int vop_set_bcsh_hue(struct rk_lcdc_driver *dev_drv,
+                           int sin_hue, int cos_hue)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u64 val;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               /*
+                * config range is [0, 510), typical value is 256
+                * register range is [0, 255], cos_hue typical value is 128
+                * sin_hue typical value is 0
+                */
+               val = V_SIN_HUE(sin_hue >> 1) | V_COS_HUE(cos_hue >> 1);
+               vop_msk_reg(vop_dev, BCSH_H, val);
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_set_bcsh_bcs(struct rk_lcdc_driver *dev_drv,
+                           bcsh_bcs_mode mode, int value)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u64 val = 0;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               switch (mode) {
+               case BRIGHTNESS:
+                       /*
+                        * user range is [0, 255], typical value is 128
+                        * register range is [-32, 31], typical value is 0
+                        */
+                       value >>= 2; /* 0-->32-->63 for user, typical is 32 */
+                       if (value < 0x20)
+                               value += 0x20;
+                       else if (value >= 0x20)
+                               value = value - 0x20;
+                       val = V_BRIGHTNESS(value);
+                       break;
+               case CONTRAST:
+                       /*
+                        * config range is [0, 510), typical value is 256
+                        * register range is [0, 255], typical value is 128
+                        */
+                       value >>= 1;
+                       val = V_CONTRAST(value);
+                       break;
+               case SAT_CON:
+                       /*
+                        * config range is [0, 1015], typical value is 512
+                        * register range is [0, 255], typical value is 128
+                        */
+                       value >>= 2;
+                       val = V_SAT_CON(value);
+                       break;
+               default:
+                       break;
+               }
+               vop_msk_reg(vop_dev, BCSH_BCS, val);
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return val;
+}
+
+static int vop_get_bcsh_bcs(struct rk_lcdc_driver *dev_drv, bcsh_bcs_mode mode)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+       u64 val = 0;
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               val = vop_readl(vop_dev, BCSH_BCS);
+               switch (mode) {
+               case BRIGHTNESS:
+                       val &= MASK(BRIGHTNESS);
+                       if (val >= 0x20)
+                               val -= 0x20;
+                       else
+                               val += 0x20;
+                       val <<= 2;
+                       break;
+               case CONTRAST:
+                       val &= MASK(CONTRAST);
+                       val >>= 8;
+                       val <<= 1;
+                       break;
+               case SAT_CON:
+                       val &= MASK(SAT_CON);
+                       val >>= 16;
+                       val <<= 2;
+                       break;
+               default:
+                       break;
+               }
+       }
+       spin_unlock(&vop_dev->reg_lock);
+       return val;
+}
+
+static int vop_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       spin_lock(&vop_dev->reg_lock);
+       if (likely(vop_dev->clk_on)) {
+               if (open) {
+                       vop_writel(vop_dev, BCSH_BCS,
+                                  V_BRIGHTNESS(0x00) | V_CONTRAST(0x80) |
+                                  V_SAT_CON(0x80));
+                       vop_writel(vop_dev, BCSH_H,
+                                  V_SIN_HUE(0x00) | V_COS_HUE(0x80));
+                       vop_msk_reg(vop_dev, BCSH_CTRL, V_BCSH_EN(1) |
+                                   V_VIDEO_MODE(BCSH_MODE_VIDEO));
+                       dev_drv->bcsh.enable = 1;
+               } else {
+                       vop_msk_reg(vop_dev, BCSH_CTRL, V_BCSH_EN(0));
+                       dev_drv->bcsh.enable = 0;
+               }
+               vop_bcsh_path_sel(dev_drv);
+               vop_cfg_done(vop_dev);
+       }
+       spin_unlock(&vop_dev->reg_lock);
+
+       return 0;
+}
+
+static int vop_set_bcsh(struct rk_lcdc_driver *dev_drv, bool enable)
+{
+       if (!enable || !dev_drv->bcsh.enable) {
+               vop_open_bcsh(dev_drv, false);
+               return 0;
+       }
+
+       if (dev_drv->bcsh.brightness <= 255 ||
+           dev_drv->bcsh.contrast < 510 ||
+           dev_drv->bcsh.sat_con <= 1015 ||
+           (dev_drv->bcsh.sin_hue < 510 && dev_drv->bcsh.cos_hue < 510)) {
+               vop_open_bcsh(dev_drv, true);
+               if (dev_drv->bcsh.brightness <= 255)
+                       vop_set_bcsh_bcs(dev_drv, BRIGHTNESS,
+                                        dev_drv->bcsh.brightness);
+               if (dev_drv->bcsh.contrast < 510)
+                       vop_set_bcsh_bcs(dev_drv, CONTRAST,
+                                        dev_drv->bcsh.contrast);
+               if (dev_drv->bcsh.sat_con <= 1015)
+                       vop_set_bcsh_bcs(dev_drv, SAT_CON,
+                                        dev_drv->bcsh.sat_con);
+               if (dev_drv->bcsh.sin_hue < 510 &&
+                   dev_drv->bcsh.cos_hue < 510)
+                       vop_set_bcsh_hue(dev_drv, dev_drv->bcsh.sin_hue,
+                                        dev_drv->bcsh.cos_hue);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused
+vop_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
+{
+       struct vop_device *vop_dev = to_vop_dev(dev_drv);
+
+       if (enable) {
+               spin_lock(&vop_dev->reg_lock);
+               if (likely(vop_dev->clk_on)) {
+                       vop_msk_reg(vop_dev, DSP_CTRL0, V_DSP_BLACK_EN(1));
+                       vop_cfg_done(vop_dev);
+               }
+               spin_unlock(&vop_dev->reg_lock);
+       } else {
+               spin_lock(&vop_dev->reg_lock);
+               if (likely(vop_dev->clk_on)) {
+                       vop_msk_reg(vop_dev, DSP_CTRL0, V_DSP_BLACK_EN(0));
+                       vop_cfg_done(vop_dev);
+               }
+               spin_unlock(&vop_dev->reg_lock);
+       }
+
+       return 0;
+}
+
+static struct rk_lcdc_drv_ops lcdc_drv_ops = {
+       .open = vop_open,
+       .win_direct_en = vop_win_direct_en,
+       .load_screen = vop_load_screen,
+       .get_dspbuf_info = vop_get_dspbuf_info,
+       .post_dspbuf = vop_post_dspbuf,
+       .set_par = vop_set_par,
+       .pan_display = vop_pan_display,
+       .direct_set_addr = vop_direct_set_win_addr,
+       .blank = vop_blank,
+       .ioctl = vop_ioctl,
+       .suspend = vop_early_suspend,
+       .resume = vop_early_resume,
+       .get_win_state = vop_get_win_state,
+       .area_support_num = vop_get_area_num,
+       .ovl_mgr = vop_ovl_mgr,
+       .get_disp_info = vop_get_disp_info,
+       .fps_mgr = vop_fps_mgr,
+       .fb_get_win_id = vop_get_win_id,
+       .fb_win_remap = vop_fb_win_remap,
+       .poll_vblank = vop_poll_vblank,
+       .dpi_open = vop_dpi_open,
+       .dpi_win_sel = vop_dpi_win_sel,
+       .dpi_status = vop_dpi_status,
+       .get_dsp_addr = vop_get_dsp_addr,
+       .set_dsp_bcsh_hue = vop_set_bcsh_hue,
+       .set_dsp_bcsh_bcs = vop_set_bcsh_bcs,
+       .get_dsp_bcsh_hue = vop_get_bcsh_hue,
+       .get_dsp_bcsh_bcs = vop_get_bcsh_bcs,
+       .open_bcsh = vop_open_bcsh,
+       .set_dsp_lut = vop_set_lut,
+       .set_hwc_lut = vop_set_hwc_lut,
+       .dump_reg = vop_reg_dump,
+       .cfg_done = vop_config_done,
+       .set_irq_to_cpu = vop_set_irq_to_cpu,
+       /*.dsp_black = vop_dsp_black,*/
+       .backlight_close = vop_backlight_close,
+       .mmu_en = vop_mmu_enable,
+};
+
+static irqreturn_t vop_isr(int irq, void *dev_id)
+{
+       struct vop_device *vop_dev = (struct vop_device *)dev_id;
+       ktime_t timestamp = ktime_get();
+       u32 intr_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vop_dev->irq_lock, flags);
+
+       intr_status = vop_readl(vop_dev, INTR_STATUS);
+       vop_mask_writel(vop_dev, INTR_CLEAR, INTR_MASK, intr_status);
+
+       spin_unlock_irqrestore(&vop_dev->irq_lock, flags);
+
+       intr_status &= 0xffff;  /* ignore raw status at 16~32bit */
+       /* This is expected for vop iommu irqs, since the irq is shared */
+       if (!intr_status)
+               return IRQ_NONE;
+
+       if (intr_status & INTR_FS0) {
+               timestamp = ktime_get();
+               vop_dev->driver.vsync_info.timestamp = timestamp;
+               wake_up_interruptible_all(&vop_dev->driver.vsync_info.wait);
+               complete(&vop_dev->sync.frmst);
+               intr_status &= ~INTR_FS0;
+       }
+
+       /* fs1 interrupt occur only when the address is different */
+       if (intr_status & INTR_FS1)
+               intr_status &= ~INTR_FS1;
+
+       if (intr_status & INTR_ADDR_SAME)
+               intr_status &= ~INTR_ADDR_SAME;
+
+       if (intr_status & INTR_DSP_HOLD_VALID) {
+               complete(&vop_dev->sync.stdbyfin);
+               intr_status &= ~INTR_DSP_HOLD_VALID;
+       }
+
+       if (intr_status & INTR_LINE_FLAG0)
+               intr_status &= ~INTR_LINE_FLAG0;
+
+       if (intr_status & INTR_LINE_FLAG1)
+               intr_status &= ~INTR_LINE_FLAG1;
+
+       if (intr_status & INTR_BUS_ERROR) {
+               intr_status &= ~INTR_BUS_ERROR;
+               dev_warn_ratelimited(vop_dev->dev, "bus error!");
+       }
+
+       if (intr_status & INTR_WIN0_EMPTY) {
+               intr_status &= ~INTR_WIN0_EMPTY;
+               dev_warn_ratelimited(vop_dev->dev, "intr win0 empty!");
+       }
+
+       if (intr_status & INTR_WIN1_EMPTY) {
+               intr_status &= ~INTR_WIN1_EMPTY;
+               dev_warn_ratelimited(vop_dev->dev, "intr win1 empty!");
+       }
+
+       if (intr_status & INTR_DMA_FINISH)
+               intr_status &= ~INTR_DMA_FINISH;
+
+       if (intr_status & INTR_MMU_STATUS)
+               intr_status &= ~INTR_MMU_STATUS;
+
+       if (intr_status)
+               dev_err(vop_dev->dev, "Unknown VOP IRQs: %#02x\n", intr_status);
+
+       return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_PM)
+static int vop_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int vop_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define vop_suspend NULL
+#define vop_resume  NULL
+#endif
+
+static int vop_parse_dt(struct vop_device *vop_dev)
+{
+       struct device_node *np = vop_dev->dev->of_node;
+       struct rk_lcdc_driver *dev_drv = &vop_dev->driver;
+       int val;
+
+       if (of_property_read_u32(np, "rockchip,prop", &val))
+               vop_dev->prop = PRMRY;  /*default set it as primary */
+       else
+               vop_dev->prop = val;
+
+       if (of_property_read_u32(np, "rockchip,mirror", &val))
+               dev_drv->rotate_mode = NO_MIRROR;
+       else
+               dev_drv->rotate_mode = val;
+
+       if (of_property_read_u32(np, "rockchip,pwr18", &val))
+               /*default set it as 3.xv power supply */
+               vop_dev->pwr18 = false;
+       else
+               vop_dev->pwr18 = (val ? true : false);
+
+       if (of_property_read_u32(np, "rockchip,fb-win-map", &val))
+               dev_drv->fb_win_map = FB_DEFAULT_ORDER;
+       else
+               dev_drv->fb_win_map = val;
+
+       if (of_property_read_u32(np, "rockchip,bcsh-en", &val))
+               dev_drv->bcsh.enable = false;
+       else
+               dev_drv->bcsh.enable = (val ? true : false);
+
+       if (of_property_read_u32(np, "rockchip,brightness", &val))
+               dev_drv->bcsh.brightness = 0xffff;
+       else
+               dev_drv->bcsh.brightness = val;
+
+       if (of_property_read_u32(np, "rockchip,contrast", &val))
+               dev_drv->bcsh.contrast = 0xffff;
+       else
+               dev_drv->bcsh.contrast = val;
+
+       if (of_property_read_u32(np, "rockchip,sat-con", &val))
+               dev_drv->bcsh.sat_con = 0xffff;
+       else
+               dev_drv->bcsh.sat_con = val;
+
+       if (of_property_read_u32(np, "rockchip,hue", &val)) {
+               dev_drv->bcsh.sin_hue = 0xffff;
+               dev_drv->bcsh.cos_hue = 0xffff;
+       } else {
+               dev_drv->bcsh.sin_hue = val & 0xff;
+               dev_drv->bcsh.cos_hue = (val >> 8) & 0xff;
+       }
+
+       if (of_property_read_u32(np, "rockchip,iommu-enabled", &val))
+               dev_drv->iommu_enabled = 0;
+       else
+               dev_drv->iommu_enabled = val;
+
+       return 0;
+}
+
+static int vop_probe(struct platform_device *pdev)
+{
+       struct vop_device *vop_dev = NULL;
+       struct rk_lcdc_driver *dev_drv;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct device_node *np = pdev->dev.of_node;
+       int prop;
+       int ret = 0;
+
+       /*
+        * if the primary lcdc has not registered ,the extend
+        * lcdc register later
+        */
+       of_property_read_u32(np, "rockchip,prop", &prop);
+       if (prop == EXTEND) {
+               if (!is_prmry_rk_lcdc_registered())
+                       return -EPROBE_DEFER;
+       }
+       vop_dev = devm_kzalloc(dev, sizeof(struct vop_device), GFP_KERNEL);
+       if (!vop_dev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, vop_dev);
+       vop_dev->dev = dev;
+       vop_parse_dt(vop_dev);
+
+       /* enable power domain */
+       pm_runtime_enable(dev);
+
+       vop_dev->hclk = devm_clk_get(vop_dev->dev, "hclk_vop");
+       if (IS_ERR(vop_dev->hclk)) {
+               dev_err(vop_dev->dev, "failed to get hclk source\n");
+               return PTR_ERR(vop_dev->hclk);
+       }
+       vop_dev->aclk = devm_clk_get(vop_dev->dev, "aclk_vop");
+       if (IS_ERR(vop_dev->aclk)) {
+               dev_err(vop_dev->dev, "failed to get aclk source\n");
+               return PTR_ERR(vop_dev->aclk);
+       }
+       vop_dev->dclk = devm_clk_get(vop_dev->dev, "dclk_vop");
+       if (IS_ERR(vop_dev->dclk)) {
+               dev_err(vop_dev->dev, "failed to get dclk source\n");
+               return PTR_ERR(vop_dev->dclk);
+       }
+       clk_prepare(vop_dev->hclk);
+       clk_prepare(vop_dev->aclk);
+       clk_prepare(vop_dev->dclk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       vop_dev->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(vop_dev->regs)) {
+               ret = PTR_ERR(vop_dev->regs);
+               goto err_exit;
+       }
+
+       vop_dev->reg_phy_base = res->start;
+       vop_dev->len = resource_size(res);
+       vop_dev->regsbak = devm_kzalloc(dev, vop_dev->len, GFP_KERNEL);
+       if (!vop_dev->regsbak) {
+               ret = -ENOMEM;
+               goto err_exit;
+       }
+
+       vop_dev->hwc_lut_addr_base = (vop_dev->regs + HWC_LUT_ADDR);
+       vop_dev->dsp_lut_addr_base = (vop_dev->regs + GAMMA_LUT_ADDR);
+       vop_dev->grf_base = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+       if (IS_ERR(vop_dev->grf_base)) {
+               dev_err(vop_dev->dev, "ERROR!! can't find grf reg property\n");
+               vop_dev->grf_base = NULL;
+       }
+
+       vop_dev->id = 1;
+       dev_set_name(vop_dev->dev, "vop%d", vop_dev->id);
+       dev_drv = &vop_dev->driver;
+       dev_drv->dev = dev;
+       dev_drv->prop = prop;
+       dev_drv->id = vop_dev->id;
+       dev_drv->ops = &lcdc_drv_ops;
+       dev_drv->lcdc_win_num = ARRAY_SIZE(vop_win);
+       dev_drv->reserved_fb = 0;
+       spin_lock_init(&vop_dev->reg_lock);
+       spin_lock_init(&vop_dev->irq_lock);
+       init_completion(&vop_dev->sync.stdbyfin);
+       init_completion(&vop_dev->sync.frmst);
+       vop_dev->sync.stdbyfin_to = 50; /* timeout 50 ms */
+       vop_dev->sync.frmst_to = 50;
+
+       vop_dev->irq = platform_get_irq(pdev, 0);
+       if (vop_dev->irq < 0) {
+               dev_err(dev, "cannot find IRQ for lcdc%d\n", vop_dev->id);
+               ret = vop_dev->irq;
+               goto err_exit;
+       }
+
+       ret = devm_request_irq(dev, vop_dev->irq, vop_isr,
+                              IRQF_SHARED,
+                              dev_name(dev), vop_dev);
+       if (ret) {
+               dev_err(dev, "cannot requeset irq %d - err %d\n",
+                       vop_dev->irq, ret);
+               goto err_exit;
+       }
+
+       if (dev_drv->iommu_enabled)
+               strcpy(dev_drv->mmu_dts_name, VOPL_IOMMU_COMPATIBLE_NAME);
+
+       ret = rk_fb_register(dev_drv, vop_win, vop_dev->id);
+       if (ret < 0) {
+               dev_err(dev, "register fb for failed!\n");
+               goto err_exit;
+       }
+       vop_dev->screen = dev_drv->screen0;
+       dev_info(dev, "lcdc%d probe ok, iommu %s\n",
+                vop_dev->id, dev_drv->iommu_enabled ? "enabled" : "disabled");
+
+       return 0;
+
+err_exit:
+       clk_unprepare(vop_dev->dclk);
+       clk_unprepare(vop_dev->aclk);
+       clk_unprepare(vop_dev->hclk);
+       pm_runtime_disable(dev);
+
+       return ret;
+}
+
+static int vop_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static void vop_shutdown(struct platform_device *pdev)
+{
+       struct vop_device *vop_dev = platform_get_drvdata(pdev);
+       struct rk_lcdc_driver *dev_drv = &vop_dev->driver;
+
+       dev_drv->suspend_flag = 1;
+       smp_wmb();
+       flush_kthread_worker(&dev_drv->update_regs_worker);
+       kthread_stop(dev_drv->update_regs_thread);
+
+       if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+               dev_drv->trsm_ops->disable();
+
+       vop_deinit(vop_dev);
+       rk_disp_pwr_disable(dev_drv);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id vop_dt_ids[] = {
+       {.compatible = "rockchip,rk3366-lcdc-lite",},
+       {}
+};
+#endif
+
+static struct platform_driver vop_driver = {
+       .probe = vop_probe,
+       .remove = vop_remove,
+       .driver = {
+                  .name = "rk-vop-lite",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(vop_dt_ids),
+                  },
+       .suspend = vop_suspend,
+       .resume = vop_resume,
+       .shutdown = vop_shutdown,
+};
+
+static int __init vop_module_init(void)
+{
+       return platform_driver_register(&vop_driver);
+}
+
+static void __exit vop_module_exit(void)
+{
+       platform_driver_unregister(&vop_driver);
+}
+
+fs_initcall(vop_module_init);
+module_exit(vop_module_exit);
diff --git a/drivers/video/rockchip/lcdc/rk_vop_lite.h b/drivers/video/rockchip/lcdc/rk_vop_lite.h
new file mode 100644 (file)
index 0000000..7b2ffe1
--- /dev/null
@@ -0,0 +1,648 @@
+#ifndef RK_VOPLITE_H_
+#define RK_VOPLITE_H_
+
+#include <linux/rk_fb.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define VOP_INPUT_MAX_WIDTH 2048
+
+/*
+ * Registers in this file
+ * REG_CFG_DONE: Register config done flag
+ * VERSION_INFO: Version for vop
+ * DSP_BG: Background color
+ * MCU_RESERVED: Reversed
+ * SYS_CTRL0: System control register0
+ * SYS_CTRL1: Axi Bus interface control register
+ * SYS_CTRL2: System control register for immediate reg
+ * DSP_CTRL0: Display control register0
+ * DSP_CTRL2: Display control register2
+ * VOP_STATUS: Some vop module status
+ * LINE_FLAG: Line flag config register
+ * INTR_EN: Interrupt enable register
+ * INTR_CLEAR: Interrupt clear register
+ * INTR_STATUS: Interrupt raw status and interrupt status
+ * WIN0_CTRL0: Win0 ctrl register0
+ * WIN0_CTRL1: Win0 ctrl register1
+ * WIN0_COLOR_KEY: Win0 color key register
+ * WIN0_VIR: Win0 virtual stride
+ * WIN0_YRGB_MST: Win0 YRGB memory start address
+ * WIN0_CBR_MST: Win0 Cbr memory start address
+ * WIN0_ACT_INFO: Win0 active window width/height
+ * WIN0_DSP_INFO: Win0 display width/height on panel
+ * WIN0_DSP_ST: Win0 display start point on panel
+ * WIN0_SCL_FACTOR_YRGB: Win0 YRGB scaling factor
+ * WIN0_SCL_FACTOR_CBR: Win0 Cbr scaling factor
+ * WIN0_SCL_OFFSET: Win0 scaling start point offset
+ * WIN0_ALPHA_CTRL: Win0 Blending control register
+ * WIN1_CTRL0: Win1 ctrl register0
+ * WIN1_CTRL1: Win1 ctrl register1
+ * WIN1_VIR: win1 virtual stride
+ * WIN1_YRGB_MST: Win1 frame buffer memory start address
+ * WIN1_DSP_INFO: Win1 display width/height on panel
+ * WIN1_DSP_ST: Win1 display start point on panel
+ * WIN1_COLOR_KEY: Win1 color key register
+ * WIN1_ALPHA_CTRL: Win1 Blending control register
+ * HWC_CTRL0: Hwc ctrl register0
+ * HWC_CTRL1: Hwc ctrl register1
+ * HWC_MST: Hwc memory start address
+ * HWC_DSP_ST: Hwc display start point on panel
+ * HWC_ALPHA_CTRL: Hwc blending control register
+ * DSP_HTOTAL_HS_END: Panel scanning horizontal width and hsync pulse end point
+ * DSP_HACT_ST_END: Panel active horizontal scanning start point and end point
+ * DSP_VTOTAL_VS_END: Panel scanning vertical height and vsync pulse end point
+ * DSP_VACT_ST_END: Panel active vertical scanning start point and end point
+ * DSP_VS_ST_END_F1: Vertical scanning start point and vsync pulse end point
+ *                   of even filed in interlace mode
+ * DSP_VACT_ST_END_F1: Vertical scanning active start point and end point of
+ *                     even filed in interlace mode
+ * BCSH_CTRL: BCSH contrl register
+ * BCSH_COLOR_BAR: Color bar config register
+ * BCSH_BCS: Brightness contrast saturation*contrast config register
+ * BCSH_H: Sin hue and cos hue config register
+ * FRC_LOWER01_0: FRC lookup table config register010
+ * FRC_LOWER01_1: FRC lookup table config register011
+ * FRC_LOWER10_0: FRC lookup table config register100
+ * FRC_LOWER10_1: FRC lookup table config register101
+ * FRC_LOWER11_0: FRC lookup table config register110
+ * FRC_LOWER11_1: FRC lookup table config register111
+ * DBG_REG_00: Current line number of dsp timing
+ * BLANKING_VALUE: The value of vsync blanking
+ * FLAG_REG_FRM_VALID: Flag reg value after frame valid
+ * FLAG_REG: Flag reg value before frame valid
+ * HWC_LUT_ADDR: Hwc lut base address
+ * GAMMA_LUT_ADDR: GAMMA lut base address
+ */
+
+static inline u64 val_mask(int val, u64 msk, int shift)
+{
+       return (msk << (shift + 32)) | ((msk & val) << shift);
+}
+
+#define VAL_MASK(x, width, shift) val_mask(x, (1 << width) - 1, shift)
+
+#define MASK(x) (V_##x(0) >> 32)
+
+#define REG_CFG_DONE                   0x00000000
+#define  V_REG_LOAD_GLOBAL_EN(x)               VAL_MASK(x, 1, 0)
+#define  V_REG_LOAD_WIN0_EN(x)                 VAL_MASK(x, 1, 1)
+#define  V_REG_LOAD_WIN1_EN(x)                 VAL_MASK(x, 1, 2)
+#define  V_REG_LOAD_HWC_EN(x)                  VAL_MASK(x, 1, 3)
+#define  V_REG_LOAD_IEP_EN(x)                  VAL_MASK(x, 1, 4)
+#define  V_REG_LOAD_SYS_EN(x)                  VAL_MASK(x, 1, 5)
+#define VERSION                                0x00000004
+#define  V_BUILD(x)                            VAL_MASK(x, 16, 0)
+#define  V_MINOR(x)                            VAL_MASK(x, 8, 16)
+#define  V_MAJOR(x)                            VAL_MASK(x, 8, 24)
+#define DSP_BG                         0x00000008
+#define  V_DSP_BG_BLUE(x)                      VAL_MASK(x, 8, 0)
+#define  V_DSP_BG_GREEN(x)                     VAL_MASK(x, 8, 8)
+#define  V_DSP_BG_RED(x)                       VAL_MASK(x, 8, 16)
+#define MCU_RESERVED                   0x0000000c
+#define SYS_CTRL0                      0x00000010
+#define  V_DIRECT_PATH_EN(x)                   VAL_MASK(x, 1, 0)
+#define  V_DIRECT_PATH_LAYER_SEL(x)            VAL_MASK(x, 1, 1)
+#define SYS_CTRL1                      0x00000014
+#define  V_SW_NOC_QOS_EN(x)                    VAL_MASK(x, 1, 0)
+#define  V_SW_NOC_QOS_VALUE(x)                 VAL_MASK(x, 2, 1)
+#define  V_SW_NOC_HURRY_EN(x)                  VAL_MASK(x, 1, 4)
+#define  V_SW_NOC_HURRY_VALUE(x)               VAL_MASK(x, 2, 5)
+#define  V_SW_NOC_HURRY_THRESHOLD(x)           VAL_MASK(x, 4, 8)
+#define  V_SW_AXI_MAX_OUTSTAND_EN(x)           VAL_MASK(x, 1, 12)
+#define  V_SW_AXI_MAX_OUTSTAND_NUM(x)          VAL_MASK(x, 5, 16)
+#define SYS_CTRL2                      0x00000018
+#define  V_IMD_AUTO_GATING_EN(x)               VAL_MASK(x, 1, 0)
+#define  V_IMD_VOP_STANDBY_EN(x)               VAL_MASK(x, 1, 1)
+#define  V_IMD_VOP_DMA_STOP(x)                 VAL_MASK(x, 1, 2)
+#define  V_IMD_DSP_OUT_ZERO(x)                 VAL_MASK(x, 1, 3)
+#define  V_IMD_YUV_CLIP(x)                     VAL_MASK(x, 1, 4)
+#define  V_IMD_DSP_DATA_OUT_MODE(x)            VAL_MASK(x, 1, 6)
+#define  V_SW_IO_PAD_CLK_SEL(x)                        VAL_MASK(x, 1, 7)
+#define  V_IMD_DSP_TIMING_IMD(x)               VAL_MASK(x, 1, 12)
+#define  V_IMD_GLOBAL_REGDONE_EN(x)            VAL_MASK(x, 1, 13)
+#define  V_FS_ADDR_MASK_EN(x)                  VAL_MASK(x, 1, 14)
+#define DSP_CTRL0                      0x00000020
+#define  V_RGB_DCLK_EN(x)                      VAL_MASK(x, 1, 0)
+#define  V_RGB_DCLK_POL(x)                     VAL_MASK(x, 1, 1)
+#define  V_RGB_HSYNC_POL(x)                    VAL_MASK(x, 1, 2)
+#define  V_RGB_VSYNC_POL(x)                    VAL_MASK(x, 1, 3)
+#define  V_RGB_DEN_POL(x)                      VAL_MASK(x, 1, 4)
+#define  V_HDMI_DCLK_EN(x)                     VAL_MASK(x, 1, 8)
+#define  V_HDMI_DCLK_POL(x)                    VAL_MASK(x, 1, 9)
+#define  V_HDMI_HSYNC_POL(x)                   VAL_MASK(x, 1, 10)
+#define  V_HDMI_VSYNC_POL(x)                   VAL_MASK(x, 1, 11)
+#define  V_HDMI_DEN_POL(x)                     VAL_MASK(x, 1, 12)
+#define  V_SW_CORE_CLK_SEL(x)                  VAL_MASK(x, 1, 13)
+#define  V_SW_HDMI_CLK_I_SEL(x)                        VAL_MASK(x, 1, 14)
+#define  V_LVDS_DCLK_EN(x)                     VAL_MASK(x, 1, 16)
+#define  V_LVDS_DCLK_POL(x)                    VAL_MASK(x, 1, 17)
+#define  V_LVDS_HSYNC_POL(x)                   VAL_MASK(x, 1, 18)
+#define  V_LVDS_VSYNC_POL(x)                   VAL_MASK(x, 1, 19)
+#define  V_LVDS_DEN_POL(x)                     VAL_MASK(x, 1, 20)
+#define  V_MIPI_DCLK_EN(x)                     VAL_MASK(x, 1, 24)
+#define  V_MIPI_DCLK_POL(x)                    VAL_MASK(x, 1, 25)
+#define  V_MIPI_HSYNC_POL(x)                   VAL_MASK(x, 1, 26)
+#define  V_MIPI_VSYNC_POL(x)                   VAL_MASK(x, 1, 27)
+#define  V_MIPI_DEN_POL(x)                     VAL_MASK(x, 1, 28)
+#define DSP_CTRL2                      0x00000028
+#define  V_DSP_INTERLACE(x)                    VAL_MASK(x, 1, 0)
+#define  V_INTERLACE_FIELD_POL(x)              VAL_MASK(x, 1, 1)
+#define  V_DITHER_UP(x)                                VAL_MASK(x, 1, 2)
+#define  V_DSP_WIN0_TOP(x)                     VAL_MASK(x, 1, 3)
+#define  V_SW_OVERLAY_MODE(x)                  VAL_MASK(x, 1, 4)
+#define  V_DSP_LUT_EN(x)                       VAL_MASK(x, 1, 5)
+#define  V_DITHER_DOWN_MODE(x)                 VAL_MASK(x, 1, 6)
+#define  V_DITHER_DOWN_SEL(x)                  VAL_MASK(x, 1, 7)
+#define  V_DITHER_DOWN(x)                      VAL_MASK(x, 1, 8)
+#define  V_DSP_BG_SWAP(x)                      VAL_MASK(x, 1, 9)
+#define  V_DSP_DELTA_SWAP(x)                   VAL_MASK(x, 1, 10)
+#define  V_DSP_RB_SWAP(x)                      VAL_MASK(x, 1, 11)
+#define  V_DSP_RG_SWAP(x)                      VAL_MASK(x, 1, 12)
+#define  V_DSP_DUMMY_SWAP(x)                   VAL_MASK(x, 1, 13)
+#define  V_DSP_BLANK_EN(x)                     VAL_MASK(x, 1, 14)
+#define  V_DSP_BLACK_EN(x)                     VAL_MASK(x, 1, 15)
+#define  V_DSP_OUT_MODE(x)                     VAL_MASK(x, 4, 16)
+#define VOP_STATUS                     0x0000002c
+#define  V_DSP_BLANKING_EN_ASYNC_AFF2(x)       VAL_MASK(x, 1, 0)
+#define  V_IDLE_MMU_FF1(x)                     VAL_MASK(x, 1, 1)
+#define  V_INT_RAW_DMA_FINISH(x)               VAL_MASK(x, 1, 2)
+#define  V_DMA_STOP_VALID(x)                   VAL_MASK(x, 1, 4)
+#define LINE_FLAG                      0x00000030
+#define  V_DSP_LINE_FLAG0_NUM(x)               VAL_MASK(x, 12, 0)
+#define  V_DSP_LINE_FLAG1_NUM(x)               VAL_MASK(x, 12, 16)
+#define INTR_EN                                0x00000034
+#define  V_FS0_INTR_EN(x)                      VAL_MASK(x, 1, 0)
+#define  V_FS1_INTR_EN(x)                      VAL_MASK(x, 1, 1)
+#define  V_ADDR_SAME_INTR_EN(x)                        VAL_MASK(x, 1, 2)
+#define  V_LINE_FLAG0_INTR_EN(x)               VAL_MASK(x, 1, 3)
+#define  V_LINE_FLAG1_INTR_EN(x)               VAL_MASK(x, 1, 4)
+#define  V_BUS_ERROR_INTR_EN(x)                        VAL_MASK(x, 1, 5)
+#define  V_WIN0_EMPTY_INTR_EN(x)               VAL_MASK(x, 1, 6)
+#define  V_WIN1_EMPTY_INTR_EN(x)               VAL_MASK(x, 1, 7)
+#define  V_DSP_HOLD_VALID_INTR_EN(x)           VAL_MASK(x, 1, 8)
+#define  V_DMA_FRM_FSH_INTR_EN(x)              VAL_MASK(x, 1, 9)
+#define INTR_CLEAR                     0x00000038
+#define  V_FS0_INTR_CLR(x)                     VAL_MASK(x, 1, 0)
+#define  V_FS1_INTR_CLR(x)                     VAL_MASK(x, 1, 1)
+#define  V_ADDR_SAME_INTR_CLR(x)               VAL_MASK(x, 1, 2)
+#define  V_LINE_FLAG0_INTR_CLR(x)              VAL_MASK(x, 1, 3)
+#define  V_LINE_FLAG1_INTR_CLR(x)              VAL_MASK(x, 1, 4)
+#define  V_BUS_ERROR_INTR_CLR(x)               VAL_MASK(x, 1, 5)
+#define  V_WIN0_EMPTY_INTR_CLR(x)              VAL_MASK(x, 1, 6)
+#define  V_WIN1_EMPTY_INTR_CLR(x)              VAL_MASK(x, 1, 7)
+#define  V_DSP_HOLD_VALID_INTR_CLR(x)          VAL_MASK(x, 1, 8)
+#define  V_DMA_FRM_FSH_INTR_CLR(x)             VAL_MASK(x, 1, 9)
+#define INTR_STATUS                    0x0000003c
+#define  V_FS0_INTR_STS(x)                     VAL_MASK(x, 1, 0)
+#define  V_FS1_INTR_STS(x)                     VAL_MASK(x, 1, 1)
+#define  V_ADDR_SAME_INTR_STS(x)               VAL_MASK(x, 1, 2)
+#define  V_LINE_FLAG0_INTR_STS(x)              VAL_MASK(x, 1, 3)
+#define  V_LINE_FLAG1_INTR_STS(x)              VAL_MASK(x, 1, 4)
+#define  V_BUS_ERROR_INTR_STS(x)               VAL_MASK(x, 1, 5)
+#define  V_WIN0_EMPTY_INTR_STS(x)              VAL_MASK(x, 1, 6)
+#define  V_WIN1_EMPTY_INTR_STS(x)              VAL_MASK(x, 1, 7)
+#define  V_DSP_HOLD_VALID_INTR_STS(x)          VAL_MASK(x, 1, 8)
+#define  V_DMA_FRM_FSH_INTR_STS(x)             VAL_MASK(x, 1, 9)
+#define  V_MMU_INTR_STATUS(x)                  VAL_MASK(x, 1, 15)
+#define  V_FS0_INTR_RAW_STS(x)                 VAL_MASK(x, 1, 16)
+#define  V_FS1_INTR_RAW_STS(x)                 VAL_MASK(x, 1, 17)
+#define  V_ADDR_SAME_INTR_RAW_STS(x)           VAL_MASK(x, 1, 18)
+#define  V_LINE_FLAG0_INTR_RAW_STS(x)          VAL_MASK(x, 1, 19)
+#define  V_LINE_FLAG1_INTR_RAW_STS(x)          VAL_MASK(x, 1, 20)
+#define  V_BUS_ERROR_INTR_RAW_STS(x)           VAL_MASK(x, 1, 21)
+#define  V_WIN0_EMPTY_INTR_RAW_STS(x)          VAL_MASK(x, 1, 22)
+#define  V_WIN1_EMPTY_INTR_RAW_STS(x)          VAL_MASK(x, 1, 23)
+#define  V_DSP_HOLD_VALID_INTR_RAW_STS(x)      VAL_MASK(x, 1, 24)
+#define  V_DMA_FRM_FSH_INTR_RAW_STS(x)         VAL_MASK(x, 1, 25)
+#define WIN0_CTRL0                     0x00000050
+#define  V_WIN0_EN(x)                          VAL_MASK(x, 1, 0)
+#define  V_WIN0_DATA_FMT(x)                    VAL_MASK(x, 3, 1)
+#define  V_WIN0_INTERLACE_READ(x)              VAL_MASK(x, 1, 8)
+#define  V_WIN0_NO_OUTSTANDING(x)              VAL_MASK(x, 1, 9)
+#define  V_WIN0_CSC_MODE(x)                    VAL_MASK(x, 2, 10)
+#define  V_WIN0_RB_SWAP(x)                     VAL_MASK(x, 1, 12)
+#define  V_WIN0_ALPHA_SWAP(x)                  VAL_MASK(x, 1, 13)
+#define  V_WIN0_MID_SWAP(x)                    VAL_MASK(x, 1, 14)
+#define  V_WIN0_UV_SWAP(x)                     VAL_MASK(x, 1, 15)
+#define  V_WIN0_YRGB_DEFLICK(x)                        VAL_MASK(x, 1, 18)
+#define  V_WIN0_CBR_DEFLICK(x)                 VAL_MASK(x, 1, 19)
+#define WIN0_CTRL1                     0x00000054
+#define  V_WIN0_YRGB_AXI_GATHER_EN(x)          VAL_MASK(x, 1, 0)
+#define  V_WIN0_CBR_AXI_GATHER_EN(x)           VAL_MASK(x, 1, 1)
+#define  V_WIN0_DMA_BURST_LENGTH(x)            VAL_MASK(x, 2, 2)
+#define  V_WIN0_YRGB_AXI_GATHER_NUM(x)         VAL_MASK(x, 4, 4)
+#define  V_WIN0_CBR_AXI_GATHER_NUM(x)          VAL_MASK(x, 3, 8)
+#define  V_SW_WIN0_YRGB0_RID(x)                        VAL_MASK(x, 4, 12)
+#define  V_SW_WIN0_CBR0_RID(x)                 VAL_MASK(x, 4, 16)
+#define WIN0_COLOR_KEY                 0x00000058
+#define  V_WIN0_KEY_COLOR(x)                   VAL_MASK(x, 24, 0)
+#define  V_WIN0_KEY_EN(x)                      VAL_MASK(x, 1, 24)
+#define WIN0_VIR                       0x0000005c
+#define  V_WIN0_YRGB_VIR_STRIDE(x)             VAL_MASK(x, 13, 0)
+#define  V_WIN0_CBR_VIR_STRIDE(x)              VAL_MASK(x, 13, 16)
+#define WIN0_YRGB_MST                  0x00000060
+#define WIN0_CBR_MST                   0x00000064
+#define WIN0_ACT_INFO                  0x00000068
+#define  V_WIN0_ACT_WIDTH(x)                   VAL_MASK(x, 13, 0)
+#define  V_WIN0_ACT_HEIGHT(x)                  VAL_MASK(x, 13, 16)
+#define WIN0_DSP_INFO                  0x0000006c
+#define  V_WIN0_DSP_WIDTH(x)                   VAL_MASK(x, 11, 0)
+#define  V_WIN0_DSP_HEIGHT(x)                  VAL_MASK(x, 11, 16)
+#define WIN0_DSP_ST                    0x00000070
+#define  V_WIN0_DSP_XST(x)                     VAL_MASK(x, 12, 0)
+#define  V_WIN0_DSP_YST(x)                     VAL_MASK(x, 12, 16)
+#define WIN0_SCL_FACTOR_YRGB           0x00000074
+#define  V_WIN0_HS_FACTOR_YRGB(x)              VAL_MASK(x, 16, 0)
+#define  V_WIN0_VS_FACTOR_YRGB(x)              VAL_MASK(x, 16, 16)
+#define WIN0_SCL_FACTOR_CBR            0x00000078
+#define  V_WIN0_HS_FACTOR_CBR(x)               VAL_MASK(x, 16, 0)
+#define  V_WIN0_VS_FACTOR_CBR(x)               VAL_MASK(x, 16, 16)
+#define WIN0_SCL_OFFSET                        0x0000007c
+#define  V_WIN0_HS_OFFSET_YRGB(x)              VAL_MASK(x, 8, 0)
+#define  V_WIN0_HS_OFFSET_CBR(x)               VAL_MASK(x, 8, 8)
+#define  V_WIN0_VS_OFFSET_YRGB(x)              VAL_MASK(x, 8, 16)
+#define  V_WIN0_VS_OFFSET_CBR(x)               VAL_MASK(x, 8, 24)
+#define WIN0_ALPHA_CTRL                        0x00000080
+#define  V_WIN0_ALPHA_EN(x)                    VAL_MASK(x, 1, 0)
+#define  V_WIN0_ALPHA_MODE(x)                  VAL_MASK(x, 1, 1)
+#define  V_WIN0_ALPHA_PRE_MUL(x)               VAL_MASK(x, 1, 2)
+#define  V_WIN0_ALPHA_SAT_MODE(x)              VAL_MASK(x, 1, 3)
+#define  V_WIN0_ALPHA_VALUE(x)                 VAL_MASK(x, 8, 4)
+#define WIN1_CTRL0                     0x00000090
+#define  V_WIN1_EN(x)                          VAL_MASK(x, 1, 0)
+#define  V_WIN1_CSC_MODE(x)                    VAL_MASK(x, 1, 2)
+#define  V_WIN1_DATA_FMT(x)                    VAL_MASK(x, 3, 4)
+#define  V_WIN1_INTERLACE_READ(x)              VAL_MASK(x, 1, 8)
+#define  V_WIN1_NO_OUTSTANDING(x)              VAL_MASK(x, 1, 9)
+#define  V_WIN1_RB_SWAP(x)                     VAL_MASK(x, 1, 12)
+#define  V_WIN1_ALPHA_SWAP(x)                  VAL_MASK(x, 1, 13)
+#define  V_WIN1_ENDIAN_SWAP(x)                 VAL_MASK(x, 1, 14)
+#define WIN1_CTRL1                     0x00000094
+#define  V_WIN1_AXI_GATHER_EN(x)               VAL_MASK(x, 1, 0)
+#define  V_WIN1_DMA_BURST_LENGTH(x)            VAL_MASK(x, 2, 2)
+#define  V_WIN1_AXI_GATHER_NUM(x)              VAL_MASK(x, 4, 4)
+#define  V_SW_WIN1_RID(x)                      VAL_MASK(x, 4, 8)
+#define WIN1_VIR                       0x00000098
+#define  V_WIN1_VIR_STRIDE(x)                  VAL_MASK(x, 13, 0)
+#define WIN1_YRGB_MST                  0x000000a0
+#define WIN1_DSP_INFO                  0x000000a4
+#define  V_WIN1_DSP_WIDTH(x)                   VAL_MASK(x, 11, 0)
+#define  V_WIN1_DSP_HEIGHT(x)                  VAL_MASK(x, 11, 16)
+#define WIN1_DSP_ST                    0x000000a8
+#define  V_WIN1_DSP_XST(x)                     VAL_MASK(x, 12, 0)
+#define  V_WIN1_DSP_YST(x)                     VAL_MASK(x, 12, 16)
+#define WIN1_COLOR_KEY                 0x000000ac
+#define  V_WIN1_KEY_COLOR(x)                   VAL_MASK(x, 24, 0)
+#define  V_WIN1_KEY_EN(x)                      VAL_MASK(x, 1, 24)
+#define WIN1_ALPHA_CTRL                        0x000000bc
+#define  V_WIN1_ALPHA_EN(x)                    VAL_MASK(x, 1, 0)
+#define  V_WIN1_ALPHA_MODE(x)                  VAL_MASK(x, 1, 1)
+#define  V_WIN1_ALPHA_PRE_MUL(x)               VAL_MASK(x, 1, 2)
+#define  V_WIN1_ALPHA_SAT_MODE(x)              VAL_MASK(x, 1, 3)
+#define  V_WIN1_ALPHA_VALUE(x)                 VAL_MASK(x, 8, 4)
+#define HWC_CTRL0                      0x000000e0
+#define  V_HWC_EN(x)                           VAL_MASK(x, 1, 0)
+#define  V_HWC_SIZE(x)                         VAL_MASK(x, 1, 1)
+#define  V_HWC_LOAD_EN(x)                      VAL_MASK(x, 1, 2)
+#define  V_HWC_LUT_EN(x)                       VAL_MASK(x, 1, 3)
+#define  V_SW_HWC_RID(x)                       VAL_MASK(x, 4, 4)
+#define HWC_CTRL1                      0x000000e4
+#define HWC_MST                                0x000000e8
+#define HWC_DSP_ST                     0x000000ec
+#define  V_HWC_DSP_XST(x)                      VAL_MASK(x, 12, 0)
+#define  V_HWC_DSP_YST(x)                      VAL_MASK(x, 12, 16)
+#define HWC_ALPHA_CTRL                 0x000000f0
+#define  V_HWC_ALPHA_EN(x)                     VAL_MASK(x, 1, 0)
+#define  V_HWC_ALPHA_MODE(x)                   VAL_MASK(x, 1, 1)
+#define  V_HWC_ALPHA_PRE_MUL(x)                        VAL_MASK(x, 1, 2)
+#define  V_HWC_ALPHA_SAT_MODE(x)               VAL_MASK(x, 1, 3)
+#define  V_HWC_ALPHA_VALUE(x)                  VAL_MASK(x, 8, 4)
+#define DSP_HTOTAL_HS_END              0x00000100
+#define  V_DSP_HS_END(x)                       VAL_MASK(x, 12, 0)
+#define  V_DSP_HTOTAL(x)                       VAL_MASK(x, 12, 16)
+#define DSP_HACT_ST_END                        0x00000104
+#define  V_DSP_HACT_END(x)                     VAL_MASK(x, 12, 0)
+#define  V_DSP_HACT_ST(x)                      VAL_MASK(x, 12, 16)
+#define DSP_VTOTAL_VS_END              0x00000108
+#define  V_DSP_VS_END(x)                       VAL_MASK(x, 12, 0)
+#define  V_DSP_VTOTAL(x)                       VAL_MASK(x, 12, 16)
+#define DSP_VACT_ST_END                        0x0000010c
+#define  V_DSP_VACT_END(x)                     VAL_MASK(x, 12, 0)
+#define  V_DSP_VACT_ST(x)                      VAL_MASK(x, 12, 16)
+#define DSP_VS_ST_END_F1               0x00000110
+#define  V_DSP_VS_END_F1(x)                    VAL_MASK(x, 12, 0)
+#define  V_DSP_VS_ST_F1(x)                     VAL_MASK(x, 12, 16)
+#define DSP_VACT_ST_END_F1             0x00000114
+#define  V_DSP_VACT_END_F1(x)                  VAL_MASK(x, 12, 0)
+#define  V_DSP_VACT_ST_F1(x)                   VAL_MASK(x, 12, 16)
+#define BCSH_CTRL                      0x00000160
+#define  V_BCSH_EN(x)                          VAL_MASK(x, 1, 0)
+#define  V_SW_BCSH_R2Y_CSC_MODE(x)             VAL_MASK(x, 1, 1)
+#define  V_VIDEO_MODE(x)                       VAL_MASK(x, 2, 2)
+#define  V_SW_BCSH_Y2R_CSC_MODE(x)             VAL_MASK(x, 2, 4)
+#define  V_SW_BCSH_Y2R_EN(x)                   VAL_MASK(x, 1, 6)
+#define  V_SW_BCSH_R2Y_EN(x)                   VAL_MASK(x, 1, 7)
+#define BCSH_COL_BAR                   0x00000164
+#define  V_COLOR_BAR_Y(x)                      VAL_MASK(x, 8, 0)
+#define  V_COLOR_BAR_U(x)                      VAL_MASK(x, 8, 8)
+#define  V_COLOR_BAR_V(x)                      VAL_MASK(x, 8, 16)
+#define BCSH_BCS                       0x00000168
+#define  V_BRIGHTNESS(x)                       VAL_MASK(x, 6, 0)
+#define  V_CONTRAST(x)                         VAL_MASK(x, 8, 8)
+#define  V_SAT_CON(x)                          VAL_MASK(x, 9, 16)
+#define BCSH_H                         0x0000016c
+#define  V_SIN_HUE(x)                          VAL_MASK(x, 8, 0)
+#define  V_COS_HUE(x)                          VAL_MASK(x, 8, 8)
+#define FRC_LOWER01_0                  0x00000170
+#define  V_LOWER01_FRM0(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER01_FRM1(x)                     VAL_MASK(x, 16, 16)
+#define FRC_LOWER01_1                  0x00000174
+#define  V_LOWER01_FRM2(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER01_FRM3(x)                     VAL_MASK(x, 16, 16)
+#define FRC_LOWER10_0                  0x00000178
+#define  V_LOWER10_FRM0(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER10_FRM1(x)                     VAL_MASK(x, 16, 16)
+#define FRC_LOWER10_1                  0x0000017c
+#define  V_LOWER10_FRM2(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER10_FRM3(x)                     VAL_MASK(x, 16, 16)
+#define FRC_LOWER11_0                  0x00000180
+#define  V_LOWER11_FRM0(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER11_FRM1(x)                     VAL_MASK(x, 16, 16)
+#define FRC_LOWER11_1                  0x00000184
+#define  V_LOWER11_FRM2(x)                     VAL_MASK(x, 16, 0)
+#define  V_LOWER11_FRM3(x)                     VAL_MASK(x, 16, 16)
+#define DBG_REG_000                    0x00000190
+#define BLANKING_VALUE                 0x000001f4
+#define  V_SW_BLANKING_VALUE(x)                        VAL_MASK(x, 24, 0)
+#define  V_BLANKING_VALUE_CONFIG_EN(x)         VAL_MASK(x, 1, 24)
+#define FLAG_REG_FRM_VALID             0x000001f8
+#define FLAG_REG                       0x000001fc
+#define HWC_LUT_ADDR                   0x00000600
+#define GAMMA_LUT_ADDR                 0x00000a00
+#define MMU_DTE_ADDR                   0x00000f00
+#define MMU_STATUS                     0x00000f04
+#define  V_PAGING_ENABLED(x)                   VAL_MASK(x, 1, 0)
+#define  V_PAGE_FAULT_ACTIVE(x)                        VAL_MASK(x, 1, 1)
+#define  V_STAIL_ACTIVE(x)                     VAL_MASK(x, 1, 2)
+#define  V_MMU_IDLE(x)                         VAL_MASK(x, 1, 3)
+#define  V_REPLAY_BUFFER_EMPTY(x)              VAL_MASK(x, 1, 4)
+#define  V_PAGE_FAULT_IS_WRITE(x)              VAL_MASK(x, 1, 5)
+#define MMU_COMMAND                    0x00000f08
+#define MMU_PAGE_FAULT_ADDR            0x00000f0c
+#define MMU_ZAP_ONE_LINE               0x00000f10
+#define MMU_INT_RAWSTAT                        0x00000f14
+#define  V_PAGE_FAULT(x)                       VAL_MASK(x, 1, 0)
+#define MMU_INT_CLEAR                  0x00000f18
+#define  V_PAGE_FAULT(x)                       VAL_MASK(x, 1, 0)
+#define MMU_INT_MASK                   0x00000f1c
+#define  V_PAGE_FAULT(x)                       VAL_MASK(x, 1, 0)
+#define MMU_INT_STATUS                 0x00000f20
+#define  V_PAGE_FAULT(x)                       VAL_MASK(x, 1, 0)
+#define MMU_AUTO_GATING                        0x00000f24
+#define  V_MMU_AUTO_GATING(x)                  VAL_MASK(x, 1, 0)
+#define MMU_CFG_DONE                   0x00000f28
+
+#define INTR_FS0               BIT(0)
+#define INTR_FS1               BIT(1)
+#define INTR_ADDR_SAME         BIT(2)
+#define INTR_LINE_FLAG0                BIT(3)
+#define INTR_LINE_FLAG1                BIT(4)
+#define INTR_BUS_ERROR         BIT(5)
+#define INTR_WIN0_EMPTY                BIT(6)
+#define INTR_WIN1_EMPTY                BIT(7)
+#define INTR_DSP_HOLD_VALID    BIT(8)
+#define INTR_DMA_FINISH                BIT(9)
+#define INTR_MMU_STATUS                BIT(15)
+
+#define INTR_MASK (INTR_FS0 | INTR_FS1 | INTR_ADDR_SAME | INTR_LINE_FLAG0 | \
+                       INTR_LINE_FLAG1 | INTR_BUS_ERROR | INTR_WIN0_EMPTY | \
+                       INTR_WIN1_EMPTY | INTR_DSP_HOLD_VALID | INTR_DMA_FINISH)
+
+/* GRF register for VOP source select */
+#define GRF_WEN_SHIFT(x)       (BIT(x) << 16)
+
+#define GRF_SOC_CON0           0x0400
+#define V_LVDS_VOP_SEL(x)              (((x) << 0) | GRF_WEN_SHIFT(0))
+#define V_HDMI_VOP_SEL(x)              (((x) << 1) | GRF_WEN_SHIFT(1))
+#define V_DSI0_VOP_SEL(x)              (((x) << 2) | GRF_WEN_SHIFT(2))
+
+#define GRF_SOC_CON5           0x0414
+#define V_RGB_VOP_SEL(x)               (((x) << 4) | GRF_WEN_SHIFT(4))
+
+#define GRF_IO_VSEL            0x0900
+#define V_VOP_IOVOL_SEL(x)             (((x) << 0) | GRF_WEN_SHIFT(0))
+
+struct vop_sync_obj_s {
+       struct completion stdbyfin;     /* standby finish */
+       int stdbyfin_to;
+       struct completion frmst;        /* frame start */
+       int frmst_to;
+};
+
+struct vop_device {
+       int id;
+       struct rk_lcdc_driver driver;
+       struct device *dev;
+       struct rk_screen *screen;
+
+       void __iomem *regs;
+       void *regsbak;
+       u32 reg_phy_base;
+       u32 len;
+       void __iomem *hwc_lut_addr_base;
+       void __iomem *dsp_lut_addr_base;
+       struct regmap *grf_base;
+
+       /* one time only one process allowed to config the register */
+       spinlock_t reg_lock;
+
+       int prop;       /* used for primary or extended display device */
+       bool pre_init;
+       bool pwr18;     /* if lcdc use 1.8v power supply */
+       /* if aclk or hclk is closed, access to register is not allowed */
+       bool clk_on;
+       /* active layer counter,when atv_layer_cnt = 0,disable lcdc */
+       u8 atv_layer_cnt;
+
+       unsigned int            irq;
+
+       struct clk              *hclk;  /* lcdc AHP clk */
+       struct clk              *dclk;  /* lcdc dclk */
+       struct clk              *aclk;  /* lcdc share memory frequency */
+       u32 pixclock;
+
+       u32 standby;            /* 1:standby,0:wrok */
+       u32 iommu_status;
+       struct backlight_device *backlight;
+
+       /* lock vop irq reg */
+       spinlock_t irq_lock;
+       struct vop_sync_obj_s sync;
+};
+
+static inline int vop_completion_timeout_ms(struct completion *comp, int to)
+{
+       long jiffies = msecs_to_jiffies(to);
+
+       return wait_for_completion_timeout(comp, jiffies);
+}
+
+static inline void vop_writel(struct vop_device *vop_dev, u32 offset, u32 v)
+{
+       u32 *_pv = (u32 *)vop_dev->regsbak;
+
+       _pv += (offset >> 2);
+       *_pv = v;
+       writel_relaxed(v, vop_dev->regs + offset);
+}
+
+static inline u32 vop_readl(struct vop_device *vop_dev, u32 offset)
+{
+       u32 v;
+
+       v = readl_relaxed(vop_dev->regs + offset);
+       return v;
+}
+
+static inline u32 vop_readl_backup(struct vop_device *vop_dev, u32 offset)
+{
+       u32 v;
+       u32 *_pv = (u32 *)vop_dev->regsbak;
+
+       _pv += (offset >> 2);
+       v = readl_relaxed(vop_dev->regs + offset);
+       *_pv = v;
+       return v;
+}
+
+static inline u32 vop_read_bit(struct vop_device *vop_dev, u32 offset, u64 v)
+{
+       u32 _v = readl_relaxed(vop_dev->regs + offset);
+
+       _v &= v >> 32;
+       v = (_v ? 1 : 0);
+       return v;
+}
+
+static inline void vop_set_bit(struct vop_device *vop_dev, u32 offset, u64 v)
+{
+       u32 *_pv = (u32 *)vop_dev->regsbak;
+
+       _pv += (offset >> 2);
+       (*_pv) |= v >> 32;
+       writel_relaxed(*_pv, vop_dev->regs + offset);
+}
+
+static inline void vop_clr_bit(struct vop_device *vop_dev, u32 offset, u64 v)
+{
+       u32 *_pv = (u32 *)vop_dev->regsbak;
+
+       _pv += (offset >> 2);
+       (*_pv) &= (~(v >> 32));
+       writel_relaxed(*_pv, vop_dev->regs + offset);
+}
+
+static inline void vop_msk_reg(struct vop_device *vop_dev, u32 offset, u64 v)
+{
+       u32 *_pv = (u32 *)vop_dev->regsbak;
+
+       _pv += (offset >> 2);
+       (*_pv) &= (~(v >> 32));
+       (*_pv) |= (u32)v;
+       writel_relaxed(*_pv, vop_dev->regs + offset);
+}
+
+static inline void vop_mask_writel(struct vop_device *vop_dev, u32 offset,
+                                  u32 mask, u32 v)
+{
+       v = mask << 16 | v;
+       writel_relaxed(v, vop_dev->regs + offset);
+}
+
+static inline void vop_cfg_done(struct vop_device *vop_dev)
+{
+       writel_relaxed(0x001f001f, vop_dev->regs + REG_CFG_DONE);
+       dsb(sy);
+}
+
+static inline int vop_grf_writel(struct regmap *base, u32 offset, u32 val)
+{
+       if (base)
+               regmap_write(base, offset, val);
+       dsb(sy);
+
+       return 0;
+}
+
+static inline int vop_cru_writel(struct regmap *base, u32 offset, u32 val)
+{
+       if (base)
+               regmap_write(base, offset, val);
+       dsb(sy);
+
+       return 0;
+}
+
+static inline int vop_cru_readl(struct regmap *base, u32 offset)
+{
+       u32 v;
+
+       if (base)
+               regmap_read(base, offset, &v);
+
+       return v;
+}
+
+enum dither_down_mode {
+       DITHER_888_565 = 0x0,
+       DITHER_888_666 = 0x1,
+};
+
+enum dither_down_sel {
+       DITHER_SEL_ALLEGRO = 0x0,
+       DITHER_SEL_FRC = 0x1,
+};
+
+enum _vop_r2y_csc_mode {
+       VOP_R2Y_CSC_BT601 = 0,
+       VOP_R2Y_CSC_BT709
+};
+
+enum _vop_y2r_csc_mode {
+       VOP_Y2R_CSC_MPEG = 0,
+       VOP_Y2R_CSC_HD,
+       VOP_Y2R_CSC_JPEG,
+       VOP_Y2R_CSC_BYPASS
+};
+
+enum _vop_format {
+       VOP_FORMAT_ARGB888 = 0,
+       VOP_FORMAT_RGB888,
+       VOP_FORMAT_RGB565,
+       VOP_FORMAT_YCBCR420 = 4,
+       VOP_FORMAT_YCBCR422,
+       VOP_FORMAT_YCBCR444
+};
+
+enum _bcsh_video_mode {
+       BCSH_MODE_BLACK = 0,
+       BCSH_MODE_BLUE,
+       BCSH_MODE_COLORBAR,
+       BCSH_MODE_VIDEO,
+};
+
+#define IS_YUV(x) ((x) >= VOP_FORMAT_YCBCR420)
+
+enum _vop_overlay_mode {
+       VOP_RGB_DOMAIN,
+       VOP_YUV_DOMAIN
+};
+
+/*************************************************************/
+#define CALSCALE(x, y)  \
+       (1 == (y) ? 0x1000 : ((((u32)((x) - 1)) * 0x1000) / ((y) - 1)))
+
+#endif