video: rockchip: vop: 3288: add parse dsp mode for VR
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / lcdc / rk3288_lcdc.c
index 1be30625903e0bc1f7aeef0d46d00add75e8535e..1f300c4d2bfff92d9656c554c069e3cf56cb73d8 100755 (executable)
@@ -51,6 +51,7 @@ module_param(dbg_thresd, int, S_IRUGO | S_IWUSR);
 static int rk3288_lcdc_set_bcsh(struct rk_lcdc_driver *dev_drv,
                                     bool enable);
 
+struct fb_info *rk_get_fb(int fb_id);
 /*#define WAIT_FOR_SYNC 1*/
 
 static int rk3288_lcdc_get_id(u32 phy_base)
@@ -75,23 +76,41 @@ static int rk3288_lcdc_set_lut(struct rk_lcdc_driver *dev_drv)
        u32 v,r,g,b;
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                        struct lcdc_device,driver);
-       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN, v_DSP_LUT_EN(0));
+       if (dev_drv->cur_screen->dsp_lut)
+               lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                            v_DSP_LUT_EN(0));
+       if ((dev_drv->cur_screen->cabc_lut) &&
+           (dev_drv->version == VOP_FULL_RK3288_V1_1))
+               lcdc_msk_reg(lcdc_dev, CABC_CTRL1, m_CABC_LUT_EN,
+                            v_CABC_LUT_EN(0));
        lcdc_cfg_done(lcdc_dev);
        mdelay(25);
-       for (i = 0; i < 256; i++) {
-               v = dev_drv->cur_screen->dsp_lut[i];
-               c = lcdc_dev->dsp_lut_addr_base + (i << 2);
-               b = (v & 0xff) << 2;
-               g = (v & 0xff00) << 4;
-               r = (v & 0xff0000) << 6;
-               v = r + g + b;
-               for (j = 0; j < 4; j++) {
-                       writel_relaxed(v, c);
-                       v += (1 + (1 << 10) + (1 << 20)) ;
-                       c++;
+       if (dev_drv->cur_screen->dsp_lut) {
+               for (i = 0; i < 256; i++) {
+                       v = dev_drv->cur_screen->dsp_lut[i];
+                       c = lcdc_dev->dsp_lut_addr_base + (i << 2);
+                       b = (v & 0xff) << 2;
+                       g = (v & 0xff00) << 4;
+                       r = (v & 0xff0000) << 6;
+                       v = r + g + b;
+                       for (j = 0; j < 4; j++) {
+                               writel_relaxed(v, c);
+                               v += (1 + (1 << 10) + (1 << 20));
+                               c++;
+                       }
+               }
+               lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                            v_DSP_LUT_EN(1));
+       }
+       if ((dev_drv->cur_screen->cabc_lut) &&
+           (dev_drv->version == VOP_FULL_RK3288_V1_1)) {
+               for (i = 0; i < 128; i++) {
+                       v = dev_drv->cur_screen->cabc_lut[i];
+                       lcdc_writel(lcdc_dev, i * 4 + CABC_LUT_ADDR, v);
                }
+               lcdc_msk_reg(lcdc_dev, CABC_CTRL1, m_CABC_LUT_EN,
+                            v_CABC_LUT_EN(1));
        }
-       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN, v_DSP_LUT_EN(1));
 
        return 0;
 
@@ -217,10 +236,10 @@ static int win##id##_enable(struct lcdc_device *lcdc_dev, int en) \
        val  =  v_WIN##id##_EN(en);                                     \
        lcdc_msk_reg(lcdc_dev, WIN##id##_CTRL0, msk, val);              \
        lcdc_cfg_done(lcdc_dev);                                        \
-       val = lcdc_read_bit(lcdc_dev, WIN##id##_CTRL0, msk);            \
+       /*val = lcdc_read_bit(lcdc_dev, WIN##id##_CTRL0, msk);          \
        while (val !=  (!!en))  {                                       \
                val = lcdc_read_bit(lcdc_dev, WIN##id##_CTRL0, msk);    \
-       }                                                               \
+       }*/                                                             \
        spin_unlock(&lcdc_dev->reg_lock);                               \
        return 0;                                                       \
 }
@@ -282,15 +301,85 @@ static void lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev)
 {
        int reg = 0;
        u32 val = 0;
+       struct rk_screen *screen = lcdc_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 = lcdc_dev->driver.win[0];
 
        spin_lock(&lcdc_dev->reg_lock);
-       for (reg = 0; reg < 0x1a0; reg+= 4) {
+       memcpy(lcdc_dev->regsbak, lcdc_dev->regs, FRC_LOWER11_1);
+       for (reg = 0; reg < FRC_LOWER11_1; reg += 4) {
                val = lcdc_readl(lcdc_dev, reg);
                switch (reg) {
+               case VERSION_INFO:
+                       lcdc_dev->driver.version = val;
+                       break;
                        case WIN0_ACT_INFO:
-                               win0->area[0].xact = (val & m_WIN0_ACT_WIDTH)+1;
-                               win0->area[0].yact = ((val & m_WIN0_ACT_HEIGHT)>>16)+1;
+                               win0->area[0].xact =
+                                       (val & m_WIN0_ACT_WIDTH) + 1;
+                               win0->area[0].yact =
+                                       ((val & m_WIN0_ACT_HEIGHT) >> 16) + 1;
+                               break;
+                       case WIN0_DSP_INFO:
+                               win0->area[0].xsize =
+                                       (val & m_WIN0_DSP_WIDTH) + 1;
+                               win0->area[0].ysize =
+                                       ((val & m_WIN0_DSP_HEIGHT) >> 16) + 1;
+                               break;
+                       case WIN0_DSP_ST:
+                               st_x = val & m_WIN0_DSP_XST;
+                               st_y = (val & m_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 & m_WIN0_EN;
+                               win0->area[0].fmt_cfg =
+                                       (val & m_WIN0_DATA_FMT) >> 1;
+                               win0->fmt_10 = (val & m_WIN0_FMT_10) >> 4;
+                               win0->area[0].format = win0->area[0].fmt_cfg;
+                               break;
+                       case WIN0_VIR:
+                               win0->area[0].y_vir_stride =
+                                       val & m_WIN0_VIR_STRIDE;
+                               win0->area[0].uv_vir_stride =
+                                       (val & m_WIN0_VIR_STRIDE_UV) >> 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 /* YUV */
+                                       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;
+                       case DSP_VACT_ST_END:
+                               if (support_uboot_display()) {
+                                       screen->mode.yres =
+                                       (val & 0x1fff) - ((val >> 16) & 0x1fff);
+                                       win0->area[0].ypos =
+                                       st_y - ((val >> 16) & 0x1fff);
+                               }
+                               break;
+                       case DSP_HACT_ST_END:
+                               if (support_uboot_display()) {
+                                       screen->mode.xres =
+                                       (val & 0x1fff) - ((val >> 16) & 0x1fff);
+                                       win0->area[0].xpos =
+                                       st_x - ((val >> 16) & 0x1fff);
+                               }
+                               break;
                        default:
                                break;
                }
@@ -321,12 +410,13 @@ static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
                dev_err(lcdc_dev->dev, "failed to get lcdc%d clk source\n",
                        lcdc_dev->id);
        }
-
-       rk_disp_pwr_enable(dev_drv);
+       if (!support_uboot_display())
+               rk_disp_pwr_enable(dev_drv);
        rk3288_lcdc_clk_enable(lcdc_dev);
 
        /*backup reg config at uboot*/
        lcdc_read_reg_defalut_cfg(lcdc_dev);
+       v = 0;
 #ifndef CONFIG_RK_FPGA
        if (lcdc_dev->pwr18 == true) {
                v = 0x00010001; /*bit14: 1,1.8v;0,3.3v*/
@@ -354,8 +444,9 @@ static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
        val  =  v_AUTO_GATING_EN(0);
        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask,val);
        lcdc_cfg_done(lcdc_dev);
-       if (dev_drv->iommu_enabled) /*disable win0 to workaround iommu pagefault*/
-               win0_enable(lcdc_dev, 0);
+       /*disable win0 to workaround iommu pagefault */
+       /*if (dev_drv->iommu_enabled) */
+       /*      win0_enable(lcdc_dev, 0); */
        lcdc_dev->pre_init = true;
 
 
@@ -393,6 +484,12 @@ static int rk3288_lcdc_post_cfg(struct rk_lcdc_driver *dev_drv)
        u16 post_dsp_vact_st_f1,post_dsp_vact_end_f1;
        u16 post_h_fac,post_v_fac;
 
+       screen->post_dsp_stx = x_res * (100 - dev_drv->overscan.left) / 200;
+       screen->post_dsp_sty = y_res * (100 - dev_drv->overscan.top) / 200;
+       screen->post_xsize = x_res *
+               (dev_drv->overscan.left + dev_drv->overscan.right) / 200;
+       screen->post_ysize = y_res *
+               (dev_drv->overscan.top + dev_drv->overscan.bottom) / 200;
        h_total = screen->mode.hsync_len+screen->mode.left_margin +
                  x_res + screen->mode.right_margin;
        v_total = screen->mode.vsync_len+screen->mode.upper_margin +
@@ -531,7 +628,8 @@ static int rk3288_lcdc_alpha_cfg(struct rk_lcdc_driver *dev_drv,int win_id)
        u32 mask, val;
        int ppixel_alpha,global_alpha;
        u32 src_alpha_ctl,dst_alpha_ctl;
-       ppixel_alpha = ((win->format == ARGB888)||(win->format == ABGR888)) ? 1 : 0;
+       ppixel_alpha = ((win->area[0].format == ARGB888) ||
+                       (win->area[0].format == ABGR888)) ? 1 : 0;
        global_alpha = (win->g_alpha_val == 0) ? 0 : 1; 
        alpha_config.src_global_alpha_val = win->g_alpha_val;
        win->alpha_mode = AB_SRC_OVER;
@@ -710,16 +808,19 @@ static int rk3288_win_0_1_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
        struct rk_lcdc_win *win = dev_drv->win[win_id];
        unsigned int mask, val, off;
        off = win_id * 0x40;
-       if(win->win_lb_mode == 5)
+       if((win->win_lb_mode == 5) &&
+          (dev_drv->version == VOP_FULL_RK3288_V1_0))
                win->win_lb_mode = 4;
 
        if(win->state == 1){
                mask =  m_WIN0_EN | m_WIN0_DATA_FMT | m_WIN0_FMT_10 |
-                       m_WIN0_LB_MODE | m_WIN0_RB_SWAP;
-               val  =  v_WIN0_EN(win->state) | v_WIN0_DATA_FMT(win->fmt_cfg) |
+                       m_WIN0_LB_MODE | m_WIN0_RB_SWAP | m_WIN0_UV_SWAP;
+               val  =  v_WIN0_EN(win->state) |
+                       v_WIN0_DATA_FMT(win->area[0].fmt_cfg) |
                        v_WIN0_FMT_10(win->fmt_10) | 
                        v_WIN0_LB_MODE(win->win_lb_mode) | 
-                       v_WIN0_RB_SWAP(win->swap_rb);
+                       v_WIN0_RB_SWAP(win->area[0].swap_rb) |
+                       v_WIN0_UV_SWAP(win->area[0].swap_uv);
                lcdc_msk_reg(lcdc_dev, WIN0_CTRL0+off, mask,val);       
        
                mask =  m_WIN0_BIC_COE_SEL |
@@ -794,6 +895,8 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
        struct rk_lcdc_win *win = dev_drv->win[win_id];
        struct rk_screen *screen = dev_drv->cur_screen;
        unsigned int mask, val, off;
+       struct fb_info *fb0 = rk_get_fb(0);
+
        off = (win_id-2) * 0x50;
        if((screen->y_mirror == 1)&&(win->area_num > 1)){
                rk3288_lcdc_area_swap(win,win->area_num);
@@ -801,8 +904,9 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
        
        if(win->state == 1){
                mask =  m_WIN2_EN | m_WIN2_DATA_FMT | m_WIN2_RB_SWAP;
-               val  =  v_WIN2_EN(1) | v_WIN2_DATA_FMT(win->fmt_cfg) |
-                       v_WIN2_RB_SWAP(win->swap_rb);   
+               val  =  v_WIN2_EN(1) |
+                       v_WIN2_DATA_FMT(win->area[0].fmt_cfg) |
+                       v_WIN2_RB_SWAP(win->area[0].swap_rb);
                lcdc_msk_reg(lcdc_dev,WIN2_CTRL0+off,mask,val);
                /*area 0*/
                if(win->area[0].state == 1){
@@ -825,6 +929,8 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
                        mask = m_WIN2_MST0_EN;
                        val  = v_WIN2_MST0_EN(0);
                        lcdc_msk_reg(lcdc_dev,WIN2_CTRL0+off,mask,val);
+                       lcdc_writel(lcdc_dev, WIN2_MST0 + off,
+                                   fb0->fix.smem_start);
                }
                /*area 1*/
                if(win->area[1].state == 1){
@@ -849,6 +955,8 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
                        mask = m_WIN2_MST1_EN;
                        val  = v_WIN2_MST1_EN(0);
                        lcdc_msk_reg(lcdc_dev,WIN2_CTRL0+off,mask,val);
+                       lcdc_writel(lcdc_dev, WIN2_MST1 + off,
+                                   fb0->fix.smem_start);
                }
                /*area 2*/
                if(win->area[2].state == 1){
@@ -873,6 +981,8 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
                        mask = m_WIN2_MST2_EN;
                        val  = v_WIN2_MST2_EN(0);
                        lcdc_msk_reg(lcdc_dev,WIN2_CTRL0+off,mask,val);
+                       lcdc_writel(lcdc_dev, WIN2_MST2 + off,
+                                   fb0->fix.smem_start);
                }
                /*area 3*/
                if(win->area[3].state == 1){
@@ -897,6 +1007,8 @@ static int rk3288_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv,int win_id)
                        mask = m_WIN2_MST3_EN;
                        val  = v_WIN2_MST3_EN(0);
                        lcdc_msk_reg(lcdc_dev,WIN2_CTRL0+off,mask,val);
+                       lcdc_writel(lcdc_dev, WIN2_MST3 + off,
+                                   fb0->fix.smem_start);
                }       
 
                if(win->alpha_en == 1)
@@ -960,10 +1072,7 @@ static int rk3288_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
 
 static int rk3288_lcdc_reg_restore(struct lcdc_device *lcdc_dev)
 {
-       if (lcdc_dev->driver.iommu_enabled)
-               memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x330);
-       else
-               memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x1fc);
+       memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x1fc);
        return 0;
 }
 static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
@@ -971,30 +1080,43 @@ static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
        u32 mask,val;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
-       spin_lock(&lcdc_dev->reg_lock);
-       if (likely(lcdc_dev->clk_on)) {
-               mask = m_MMU_EN;
-               val = v_MMU_EN(1);
-               lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
-               mask = m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;
-               val = v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1);
-               lcdc_msk_reg(lcdc_dev, SYS_CTRL1, mask, val);
+
+       if (unlikely(!lcdc_dev->clk_on)) {
+               pr_info("%s,clk_on = %d\n", __func__, lcdc_dev->clk_on);
+               return 0;
+       }
+       if (dev_drv->iommu_enabled) {
+               if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) {
+
+               if (likely(lcdc_dev->clk_on)) {
+                       spin_lock(&lcdc_dev->reg_lock);
+                       mask = m_MMU_EN;
+                       val = v_MMU_EN(1);
+                       lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
+                       mask = m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;
+                       val = v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1);
+                       lcdc_msk_reg(lcdc_dev, SYS_CTRL1, mask, val);
+                       spin_unlock(&lcdc_dev->reg_lock);
+       }
+                       lcdc_dev->iommu_status = 1;
+                       rockchip_iovmm_activate(dev_drv->dev);
+               }
        }
-       spin_unlock(&lcdc_dev->reg_lock);
        return 0;
 }
 
-static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
+static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv, int reset_rate)
 {
 #ifdef CONFIG_RK_FPGA
        return 0;
 #endif
-       int ret,fps;
+       int ret = 0,fps;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        struct rk_screen *screen = dev_drv->cur_screen;
 
-       ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock);
+        if (reset_rate)
+               ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock);/*set pll */
        if (ret)
                dev_err(dev_drv->dev, "set lcdc%d dclk failed\n", lcdc_dev->id);
        lcdc_dev->pixclock =
@@ -1009,9 +1131,85 @@ static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
 
 }
 
+static void rk3288_lcdc_bcsh_path_sel(struct rk_lcdc_driver *dev_drv)
+{
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+       u32 bcsh_color_bar;
+
+       if (dev_drv->output_color == COLOR_RGB) {
+               bcsh_color_bar = lcdc_readl(lcdc_dev, BCSH_COLOR_BAR);
+               if (((bcsh_color_bar & m_BCSH_EN) == 1) ||
+                   (dev_drv->bcsh.enable == 1))/*bcsh enabled */
+                       lcdc_msk_reg(lcdc_dev, BCSH_CTRL,
+                                    m_BCSH_R2Y_EN | m_BCSH_Y2R_EN,
+                                    v_BCSH_R2Y_EN(1) | v_BCSH_Y2R_EN(1));
+               else
+                       lcdc_msk_reg(lcdc_dev, BCSH_CTRL,
+                                    m_BCSH_R2Y_EN | m_BCSH_Y2R_EN,
+                                    v_BCSH_R2Y_EN(0) | v_BCSH_Y2R_EN(0));
+       } else {        /* RGB2YUV */
+               lcdc_msk_reg(lcdc_dev, BCSH_CTRL,
+                            m_BCSH_R2Y_EN | m_BCSH_Y2R_EN,
+                            v_BCSH_R2Y_EN(1) | v_BCSH_Y2R_EN(0));
+       }
+}
+
+static int rk3288_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact,
+                                 u16 *yact, int *format, u32 *dsp_addr,
+                                 int *ymirror)
+{
+       struct lcdc_device *lcdc_dev = container_of(dev_drv,
+                                                   struct lcdc_device, driver);
+       u32 val;
+
+       spin_lock(&lcdc_dev->reg_lock);
+
+       val = lcdc_readl(lcdc_dev, WIN0_ACT_INFO);
+       *xact = (val & m_WIN0_ACT_WIDTH) + 1;
+       *yact = ((val & m_WIN0_ACT_HEIGHT)>>16) + 1;
+
+       val = lcdc_readl(lcdc_dev, WIN0_CTRL0);
+       *format = (val & m_WIN0_DATA_FMT) >> 1;
+       *dsp_addr = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
+
+       spin_unlock(&lcdc_dev->reg_lock);
+
+       return 0;
+}
+
+static int rk3288_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
+                             int format, u16 xact, u16 yact, u16 xvir,
+                             int ymirror)
+{
+       struct lcdc_device *lcdc_dev = container_of(dev_drv,
+                                                   struct lcdc_device, driver);
+       u32 val, mask;
+       struct rk_lcdc_win *win = dev_drv->win[0];
+       int swap = (format == RGB888) ? 1 : 0;
+
+       mask = m_WIN0_DATA_FMT | m_WIN0_RB_SWAP;
+       val = v_WIN0_DATA_FMT(format) | v_WIN0_RB_SWAP(swap);
+       lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask, val);
+
+       lcdc_msk_reg(lcdc_dev, WIN0_VIR, m_WIN0_VIR_STRIDE,
+                       v_WIN0_VIR_STRIDE(xvir));
+       lcdc_writel(lcdc_dev, WIN0_ACT_INFO, v_WIN0_ACT_WIDTH(xact) |
+                   v_WIN0_ACT_HEIGHT(yact));
+
+       lcdc_writel(lcdc_dev, WIN0_YRGB_MST, rgb_mst);
+
+       lcdc_cfg_done(lcdc_dev);
+       win->state = 1;
+       win->last_state = 1;
+
+       return 0;
+}
+
 static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
 {
        u16 face = 0;
+       u16 dclk_ddr = 0;
        u32 v=0;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
@@ -1026,6 +1224,13 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
        u16 y_res = screen->mode.yres;
        u32 mask, val;
        u16 h_total,v_total;
+       int ret = 0;
+       int hdmi_dclk_out_en = 0;
+
+       if (unlikely(!lcdc_dev->clk_on)) {
+               pr_info("%s,clk_on = %d\n", __func__, lcdc_dev->clk_on);
+               return 0;
+       }
        
        h_total = hsync_len + left_margin  + x_res + right_margin;
        v_total = vsync_len + upper_margin + y_res + lower_margin;
@@ -1041,39 +1246,77 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                case OUT_P565:
                        face = OUT_P565;
                        mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
-                           m_DITHER_DOWN_SEL;
+                           m_DITHER_DOWN_SEL | m_DITHER_UP_EN |
+                           m_PRE_DITHER_DOWN_EN;
                        val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
-                           v_DITHER_DOWN_SEL(1);
+                           v_DITHER_DOWN_SEL(1) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                case OUT_P666:
                        face = OUT_P666;
                        mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
-                           m_DITHER_DOWN_SEL;
+                           m_DITHER_DOWN_SEL | m_DITHER_UP_EN |
+                           m_PRE_DITHER_DOWN_EN;
                        val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
-                           v_DITHER_DOWN_SEL(1);
+                           v_DITHER_DOWN_SEL(1) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                case OUT_D888_P565:
                        face = OUT_P888;
                        mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
-                           m_DITHER_DOWN_SEL;
+                           m_DITHER_DOWN_SEL | m_DITHER_UP_EN |
+                           m_PRE_DITHER_DOWN_EN;
                        val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0) |
-                           v_DITHER_DOWN_SEL(1);
+                           v_DITHER_DOWN_SEL(1) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                case OUT_D888_P666:
                        face = OUT_P888;
                        mask = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
-                           m_DITHER_DOWN_SEL;
+                           m_DITHER_DOWN_SEL | m_DITHER_UP_EN |
+                           m_PRE_DITHER_DOWN_EN;
                        val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
-                           v_DITHER_DOWN_SEL(1);
+                           v_DITHER_DOWN_SEL(1) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                case OUT_P888:
                        face = OUT_P888;
-                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
-                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN |
+                               m_PRE_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
+                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_YUV_420:
+                       hdmi_dclk_out_en = 1;
+                       face = OUT_YUV_420;
+                       dclk_ddr = 1;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN |
+                               m_PRE_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(1);
+                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_YUV_420_10BIT:
+                       hdmi_dclk_out_en = 1;
+                       face = OUT_YUV_420;
+                       dclk_ddr = 1;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN |
+                               m_PRE_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(0);
+                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
+                       break;
+               case OUT_P101010:
+                       face = OUT_P101010;
+                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN |
+                               m_PRE_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(1) |
+                           v_PRE_DITHER_DOWN_EN(0);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                default:
@@ -1083,16 +1326,20 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                switch(screen->type){
                case SCREEN_RGB:
                case SCREEN_LVDS:
-               case SCREEN_DUAL_LVDS:                  
+               case SCREEN_DUAL_LVDS:
+               case SCREEN_LVDS_10BIT:
+               case SCREEN_DUAL_LVDS_10BIT:
                        mask = m_RGB_OUT_EN;
                        val = v_RGB_OUT_EN(1);
                        v = 1 << (3+16);
                        v |= (lcdc_dev->id << 3);
-                       break;
+                       break;
                case SCREEN_HDMI:
-                       face = OUT_RGB_AAA;
+                       if ((screen->face == OUT_P888) ||
+                           (screen->face == OUT_P101010))
+                               face = OUT_P101010;/*RGB 101010 output*/
                        mask = m_HDMI_OUT_EN;
-                       val = v_HDMI_OUT_EN(1);         
+                       val = v_HDMI_OUT_EN(1);
                        break;
                case SCREEN_MIPI:
                        mask = m_MIPI_OUT_EN;
@@ -1103,14 +1350,20 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        val = v_MIPI_OUT_EN(1) | v_DOUB_CHANNEL_EN(1);  
                        break;
                case SCREEN_EDP:
-                       face = OUT_RGB_AAA;  /*RGB AAA output*/
-                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
-                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
-                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
+                       face = OUT_P101010;  /*RGB 101010 output*/
                        mask = m_EDP_OUT_EN;
-                       val = v_EDP_OUT_EN(1);          
+                       val = v_EDP_OUT_EN(1);
+                       break;
+               default:
+                       mask = 0;
+                       val = 0;
+                       pr_info("unknow screen type: %d\n", screen->type);
                        break;
                }
+               if (dev_drv->version == VOP_FULL_RK3288_V1_1) {
+                       mask |= m_HDMI_DCLK_OUT_EN;
+                       val |= v_HDMI_DCLK_OUT_EN(hdmi_dclk_out_en);
+               }
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
 #ifndef CONFIG_RK_FPGA
                writel_relaxed(v, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
@@ -1119,7 +1372,8 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                       m_DSP_DEN_POL | m_DSP_DCLK_POL | m_DSP_BG_SWAP | 
                       m_DSP_RB_SWAP | m_DSP_RG_SWAP | m_DSP_DELTA_SWAP |
                       m_DSP_DUMMY_SWAP | m_DSP_OUT_ZERO | m_DSP_BLANK_EN | 
-                      m_DSP_BLACK_EN | m_DSP_X_MIR_EN | m_DSP_Y_MIR_EN;
+                      m_DSP_BLACK_EN | m_DSP_X_MIR_EN | m_DSP_Y_MIR_EN |
+                      m_DSP_DCLK_DDR;
                val = v_DSP_OUT_MODE(face) | v_DSP_HSYNC_POL(screen->pin_hsync) |
                      v_DSP_VSYNC_POL(screen->pin_vsync) | 
                      v_DSP_DEN_POL(screen->pin_den) | v_DSP_DCLK_POL(screen->pin_dclk) |
@@ -1128,7 +1382,9 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                      v_DSP_DELTA_SWAP(screen->swap_delta) |
                      v_DSP_DUMMY_SWAP(screen->swap_dumy) | v_DSP_OUT_ZERO(0) | 
                      v_DSP_BLANK_EN(0) | v_DSP_BLACK_EN(0) |
-                     v_DSP_X_MIR_EN(screen->x_mirror) | v_DSP_Y_MIR_EN(screen->y_mirror);
+                     v_DSP_X_MIR_EN(screen->x_mirror) |
+                     v_DSP_Y_MIR_EN(screen->y_mirror) |
+                     v_DSP_DCLK_DDR(dclk_ddr);
                lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val);
 
                mask = m_DSP_BG_BLUE | m_DSP_BG_GREEN | m_DSP_BG_RED;
@@ -1154,15 +1410,29 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                lcdc_msk_reg(lcdc_dev, DSP_VACT_ST_END, mask, val);
 
                rk3288_lcdc_post_cfg(dev_drv);
+               mask = m_DSP_LINE_FLAG_NUM;
+               val = v_DSP_LINE_FLAG_NUM(vsync_len + upper_margin + y_res);
+               lcdc_msk_reg(lcdc_dev, INTR_CTRL0, mask, val);
+               dev_drv->output_color = screen->color_mode;
+               if (dev_drv->version == VOP_FULL_RK3288_V1_1) {
+                       rk3288_lcdc_bcsh_path_sel(dev_drv);
+               } else {
+                       if (dev_drv->output_color != COLOR_RGB) {
+                               pr_err("vop ver:%x,unsupport output color:%d\n",
+                                      dev_drv->version, dev_drv->output_color);
+                               ret = -1;
+                       }
+               }
        }
        spin_unlock(&lcdc_dev->reg_lock);
-       rk3288_lcdc_set_dclk(dev_drv);
-       if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
+       rk3288_lcdc_set_dclk(dev_drv, 1);
+       if (screen->type != SCREEN_HDMI && dev_drv->trsm_ops &&
+           dev_drv->trsm_ops->enable)
                dev_drv->trsm_ops->enable();
        if (screen->init)
                screen->init();
        
-       return 0;
+       return ret;
 }
 
 /*enable layer,open:1,enable;0 disable*/
@@ -1272,15 +1542,12 @@ static int rk3288_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv)
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                        struct lcdc_device, driver);
        u32 mask,val;
-       struct rk_screen *screen = dev_drv->cur_screen;
        
        mask = m_FS_INTR_CLR | m_FS_INTR_EN | m_LINE_FLAG_INTR_CLR |
                            m_LINE_FLAG_INTR_EN | m_BUS_ERROR_INTR_CLR | 
-                           m_BUS_ERROR_INTR_EN | m_DSP_LINE_FLAG_NUM;
+                           m_BUS_ERROR_INTR_EN;
        val = v_FS_INTR_CLR(1) | v_FS_INTR_EN(1) | v_LINE_FLAG_INTR_CLR(1) |
-           v_LINE_FLAG_INTR_EN(1) | v_BUS_ERROR_INTR_CLR(1) | v_BUS_ERROR_INTR_EN(0) |
-           v_DSP_LINE_FLAG_NUM(screen->mode.vsync_len + screen->mode.upper_margin +
-           screen->mode.yres);
+           v_LINE_FLAG_INTR_EN(1) | v_BUS_ERROR_INTR_CLR(1) | v_BUS_ERROR_INTR_EN(0);
        lcdc_msk_reg(lcdc_dev, INTR_CTRL0, mask, val);  
 #ifdef LCDC_IRQ_EMPTY_DEBUG
                 mask = m_WIN0_EMPTY_INTR_EN | m_WIN1_EMPTY_INTR_EN | m_WIN2_EMPTY_INTR_EN |
@@ -1307,7 +1574,7 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                rockchip_set_system_status(sys_status);
                rk3288_lcdc_pre_init(dev_drv);
                rk3288_lcdc_clk_enable(lcdc_dev);
-#if defined(CONFIG_ROCKCHIP_IOMMU)
+               rk3288_lcdc_enable_irq(dev_drv);
                if (dev_drv->iommu_enabled) {
                        if (!dev_drv->mmu_dev) {
                                dev_drv->mmu_dev =
@@ -1321,24 +1588,20 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                                        return -1;
                                }
                        }
-                       if (dev_drv->mmu_dev)
-                               rockchip_iovmm_activate(dev_drv->dev);
                }
-#endif
                rk3288_lcdc_reg_restore(lcdc_dev);
-               if (dev_drv->iommu_enabled)
-                       rk3288_lcdc_mmu_en(dev_drv);
+               /*if (dev_drv->iommu_enabled)
+                  rk3368_lcdc_mmu_en(dev_drv); */
                if ((support_uboot_display()&&(lcdc_dev->prop == PRMRY))) {
-                       rk3288_lcdc_set_dclk(dev_drv);
-                       rk3288_lcdc_enable_irq(dev_drv);
+                       rk3288_lcdc_set_dclk(dev_drv, 0);
+                       /* rk3288_lcdc_enable_irq(dev_drv); */
                } else {
                        rk3288_load_screen(dev_drv, 1);
                }
                if (dev_drv->bcsh.enable)
                        rk3288_lcdc_set_bcsh(dev_drv, 1);
                spin_lock(&lcdc_dev->reg_lock);
-               if (dev_drv->cur_screen->dsp_lut)
-                       rk3288_lcdc_set_lut(dev_drv);
+               rk3288_lcdc_set_lut(dev_drv);
                spin_unlock(&lcdc_dev->reg_lock);
        }
 
@@ -1357,12 +1620,12 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
        if ((!open) && (!lcdc_dev->atv_layer_cnt)) {
                rk3288_lcdc_disable_irq(lcdc_dev);
                rk3288_lcdc_reg_update(dev_drv);
-#if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
-                       if (dev_drv->mmu_dev)
+                       if (dev_drv->mmu_dev) {
                                rockchip_iovmm_deactivate(dev_drv->dev);
+                               lcdc_dev->iommu_status = 0;
+                       }
                }
-#endif
                rk3288_lcdc_clk_disable(lcdc_dev);
                rockchip_clear_system_status(sys_status);
        }
@@ -1429,10 +1692,18 @@ static int win2_display(struct lcdc_device *lcdc_dev,
                for(i=0;i<win->area_num;i++)
                        win->area[i].y_addr = 
                                win->area[i].smem_start + win->area[i].y_offset;
-                       lcdc_writel(lcdc_dev,WIN2_MST0,win->area[0].y_addr);
-                       lcdc_writel(lcdc_dev,WIN2_MST1,win->area[1].y_addr);
-                       lcdc_writel(lcdc_dev,WIN2_MST2,win->area[2].y_addr);
-                       lcdc_writel(lcdc_dev,WIN2_MST3,win->area[3].y_addr);
+                       if (win->area[0].state)
+                               lcdc_writel(lcdc_dev, WIN2_MST0,
+                                           win->area[0].y_addr);
+                       if (win->area[1].state)
+                               lcdc_writel(lcdc_dev, WIN2_MST1,
+                                           win->area[1].y_addr);
+                       if (win->area[2].state)
+                               lcdc_writel(lcdc_dev, WIN2_MST2,
+                                           win->area[2].y_addr);
+                       if (win->area[3].state)
+                               lcdc_writel(lcdc_dev, WIN2_MST3,
+                                           win->area[3].y_addr);
        }
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
@@ -1451,10 +1722,18 @@ static int win3_display(struct lcdc_device *lcdc_dev,
                for(i=0;i<win->area_num;i++)
                        win->area[i].y_addr = 
                                win->area[i].smem_start + win->area[i].y_offset;
-                       lcdc_writel(lcdc_dev,WIN3_MST0,win->area[0].y_addr);
-                       lcdc_writel(lcdc_dev,WIN3_MST1,win->area[1].y_addr);
-                       lcdc_writel(lcdc_dev,WIN3_MST2,win->area[2].y_addr);
-                       lcdc_writel(lcdc_dev,WIN3_MST3,win->area[3].y_addr);            
+                       if (win->area[0].state)
+                               lcdc_writel(lcdc_dev, WIN3_MST0,
+                                           win->area[0].y_addr);
+                       if (win->area[1].state)
+                               lcdc_writel(lcdc_dev, WIN3_MST1,
+                                           win->area[1].y_addr);
+                       if (win->area[2].state)
+                               lcdc_writel(lcdc_dev, WIN3_MST2,
+                                           win->area[2].y_addr);
+                       if (win->area[3].state)
+                               lcdc_writel(lcdc_dev, WIN3_MST3,
+                                           win->area[3].y_addr);
                }
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
@@ -1548,8 +1827,7 @@ static int rk3288_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
        yrgb_srcH = srcH;
        yrgb_dstW = dstW;
        yrgb_dstH = dstH;
-       if ((yrgb_dstW >= yrgb_srcW*8) || (yrgb_dstH >= yrgb_srcH*8) ||
-               (yrgb_dstW*8 <= yrgb_srcW) || (yrgb_dstH*8 <= yrgb_srcH)) {
+       if ((yrgb_dstW*8 <= yrgb_srcW) || (yrgb_dstH*8 <= yrgb_srcH)) {
                pr_err("ERROR: yrgb scale exceed 8,"
                       "srcW=%d,srcH=%d,dstW=%d,dstH=%d\n",
                       yrgb_srcW,yrgb_srcH,yrgb_dstW,yrgb_dstH);
@@ -1571,7 +1849,7 @@ static int rk3288_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
        }
 
        /*cbcr scl mode*/
-       switch (win->format) {
+       switch (win->area[0].format) {
        case YUV422:
        case YUV422_A:  
                cbcr_srcW = srcW/2;
@@ -1605,8 +1883,7 @@ static int rk3288_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
                break;
        }               
        if (yuv_fmt) {
-               if ((cbcr_dstW >= cbcr_srcW*8) || (cbcr_dstH >= cbcr_srcH*8) ||
-                       (cbcr_dstW*8 <= cbcr_srcW)||(cbcr_dstH*8 <= cbcr_srcH)) {
+               if ((cbcr_dstW*8 <= cbcr_srcW) || (cbcr_dstH*8 <= cbcr_srcH)) {
                        pr_err("ERROR: cbcr scale exceed 8,"
                       "srcW=%d,srcH=%d,dstW=%d,dstH=%d\n",
                       cbcr_srcW,cbcr_srcH,cbcr_dstW,cbcr_dstH);
@@ -1637,14 +1914,17 @@ static int rk3288_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
                win->cbr_hor_scl_mode,win->cbr_ver_scl_mode);
 
     /*line buffer mode*/
-       if((win->format == YUV422) || (win->format == YUV420) || (win->format == YUV422_A) || (win->format == YUV420_A)){
-               if(win->cbr_hor_scl_mode == SCALE_DOWN){
+       if ((win->area[0].format == YUV422) ||
+           (win->area[0].format == YUV420) ||
+           (win->area[0].format == YUV422_A) ||
+           (win->area[0].format == YUV420_A)) {
+               if (win->cbr_hor_scl_mode == SCALE_DOWN) {
                        if ((cbcr_dstW > 3840) || (cbcr_dstW == 0)) {
                                pr_err("ERROR cbcr_dstW = %d\n",cbcr_dstW);                
-                       }else if(cbcr_dstW > 2560){
+                       } else if (cbcr_dstW > 2560) {
                                win->win_lb_mode = LB_RGB_3840X2;
-                       }else if(cbcr_dstW > 1920){
-                               if(win->yrgb_hor_scl_mode == SCALE_DOWN){
+                       } else if (cbcr_dstW > 1920) {
+                               if (win->yrgb_hor_scl_mode == SCALE_DOWN) {
                                        if(yrgb_dstW > 3840){
                                                pr_err("ERROR yrgb_dst_width exceeds 3840\n");
                                        }else if(yrgb_dstW > 2560){
@@ -1654,13 +1934,13 @@ static int rk3288_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
                                        }else{
                                                pr_err("ERROR never run here!yrgb_dstW<1920 ==> cbcr_dstW>1920\n");
                                        }
-                               }
-                       }else if(cbcr_dstW > 1280){
+                               }
+                       } else if (cbcr_dstW > 1280) {
                                win->win_lb_mode = LB_YUV_3840X5;
-                       }else{
+                       } else {
                                win->win_lb_mode = LB_YUV_2560X8;
                        }            
-               } else { /*SCALE_UP or SCALE_NONE*/
+               } else { /*SCALE_UP or SCALE_NONE*/
                        if ((cbcr_srcW > 3840) || (cbcr_srcW == 0)) {
                                pr_err("ERROR cbcr_srcW = %d\n",cbcr_srcW);
                        }else if(cbcr_srcW > 2560){                
@@ -1940,7 +2220,7 @@ static int win0_set_par(struct lcdc_device *lcdc_dev,
                        struct rk_screen *screen, struct rk_lcdc_win *win)
 {
        u32 xact,yact,xvir, yvir,xpos, ypos;
-       u8 fmt_cfg = 0;
+       u8 fmt_cfg = 0, swap_rb, swap_uv = 0;
        char fmt[9] = "NULL";
 
        xpos = win->area[0].xpos + screen->mode.left_margin + screen->mode.hsync_len;
@@ -1949,55 +2229,61 @@ static int win0_set_par(struct lcdc_device *lcdc_dev,
        spin_lock(&lcdc_dev->reg_lock);
        if(likely(lcdc_dev->clk_on)){
                rk3288_lcdc_cal_scl_fac(win);/*fac,lb,gt2,gt4*/
-               switch (win->format){
+               switch (win->area[0].format) {
                case ARGB888:
                        fmt_cfg = 0;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case XBGR888:
                case ABGR888:
                        fmt_cfg = 0;
-                       win->swap_rb = 1;
+                       swap_rb = 1;
                        win->fmt_10 = 0;
                        break;
                case RGB888:
                        fmt_cfg = 1;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case RGB565:
                        fmt_cfg = 2;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case YUV422:
                        fmt_cfg = 5;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case YUV420:    
                        fmt_cfg = 4;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
+               case YUV420_NV21:
+                       fmt_cfg = 4;
+                       swap_rb = 0;
+                       swap_uv = 1;
+                       win->fmt_10 = 0;
+                       break;  
                case YUV444:    
                        fmt_cfg = 6;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                case YUV422_A:
                        fmt_cfg = 5;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;
                case YUV420_A:  
                        fmt_cfg = 4;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;
                case YUV444_A:  
                        fmt_cfg = 6;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;
                default:
@@ -2005,9 +2291,11 @@ static int win0_set_par(struct lcdc_device *lcdc_dev,
                                __func__);
                        break;
                }
-               win->fmt_cfg = fmt_cfg;
+               win->area[0].fmt_cfg = fmt_cfg;
+               win->area[0].swap_rb = swap_rb;
                win->area[0].dsp_stx = xpos;
                win->area[0].dsp_sty = ypos;
+               win->area[0].swap_uv = swap_uv;
                xact = win->area[0].xact;
                yact = win->area[0].yact;
                xvir = win->area[0].xvir;
@@ -2018,7 +2306,7 @@ static int win0_set_par(struct lcdc_device *lcdc_dev,
 
        DBG(1, "lcdc%d>>%s\n>>format:%s>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d\n"
                ">>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id,
-               __func__, get_format_string(win->format, fmt), xact,
+               __func__, get_format_string(win->area[0].format, fmt), xact,
                yact, win->area[0].xsize, win->area[0].ysize, xvir, yvir, xpos, ypos);
        return 0;
 
@@ -2027,66 +2315,72 @@ static int win0_set_par(struct lcdc_device *lcdc_dev,
 static int win1_set_par(struct lcdc_device *lcdc_dev,
                        struct rk_screen *screen, struct rk_lcdc_win *win)
 {
-       u32 xact,yact,xvir, yvir,xpos, ypos;
-       u8 fmt_cfg = 0;
+       u32 xact, yact, xvir, yvir, xpos, ypos;
+       u8 fmt_cfg = 0, swap_rb, swap_uv = 0;
        char fmt[9] = "NULL";
 
        xpos = win->area[0].xpos + screen->mode.left_margin + screen->mode.hsync_len;
        ypos = win->area[0].ypos + screen->mode.upper_margin + screen->mode.vsync_len;
 
        spin_lock(&lcdc_dev->reg_lock);
-       if(likely(lcdc_dev->clk_on)){
+       if (likely(lcdc_dev->clk_on)) {
                rk3288_lcdc_cal_scl_fac(win);/*fac,lb,gt2,gt4*/
-               switch (win->format){
+               switch (win->area[0].format) {
                case ARGB888:
                        fmt_cfg = 0;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case XBGR888:
                case ABGR888:
                        fmt_cfg = 0;
-                       win->swap_rb = 1;
+                       swap_rb = 1;
                        win->fmt_10 = 0;
                        break;
                case RGB888:
                        fmt_cfg = 1;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case RGB565:
                        fmt_cfg = 2;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case YUV422:
                        fmt_cfg = 5;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case YUV420:
                        fmt_cfg = 4;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
+                       win->fmt_10 = 0;
+                       break;
+               case YUV420_NV21:
+                       fmt_cfg = 4;
+                       swap_rb = 0;
+                       swap_uv = 1;
                        win->fmt_10 = 0;
                        break;
                case YUV444:
                        fmt_cfg = 6;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
                case YUV422_A:
                        fmt_cfg = 5;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;
                case YUV420_A:  
                        fmt_cfg = 4;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;
                case YUV444_A:  
                        fmt_cfg = 6;
-                       win->swap_rb = 0;
+                       swap_rb = 0;
                        win->fmt_10 = 1;
                        break;                  
                default:
@@ -2094,9 +2388,11 @@ static int win1_set_par(struct lcdc_device *lcdc_dev,
                                __func__);
                        break;
                }
-               win->fmt_cfg = fmt_cfg;
+               win->area[0].fmt_cfg = fmt_cfg;
+               win->area[0].swap_rb = swap_rb;
                win->area[0].dsp_stx = xpos;
                win->area[0].dsp_sty = ypos;
+               win->area[0].swap_uv = swap_uv;
                xact = win->area[0].xact;
                yact = win->area[0].yact;
                xvir = win->area[0].xvir;
@@ -2107,7 +2403,7 @@ static int win1_set_par(struct lcdc_device *lcdc_dev,
 
        DBG(1, "lcdc%d>>%s\n>>format:%s>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d\n"
                ">>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id,
-               __func__, get_format_string(win->format, fmt), xact,
+               __func__, get_format_string(win->area[0].format, fmt), xact,
                yact, win->area[0].xsize, win->area[0].ysize, xvir, yvir, xpos, ypos);
        return 0;
 
@@ -2117,28 +2413,28 @@ static int win2_set_par(struct lcdc_device *lcdc_dev,
                        struct rk_screen *screen, struct rk_lcdc_win *win)
 {
        int i;
-       u8 fmt_cfg;
+       u8 fmt_cfg, swap_rb;
 
        spin_lock(&lcdc_dev->reg_lock);
-       if(likely(lcdc_dev->clk_on)){
-               for(i=0;i<win->area_num;i++){
-                       switch (win->format){
+       if (likely(lcdc_dev->clk_on)) {
+               for (i = 0; i < win->area_num; i++) {
+                       switch (win->area[i].format) {
                        case ARGB888:
                                fmt_cfg = 0;
-                               win->swap_rb = 0;
+                               swap_rb = 0;
                                break;
                        case XBGR888:
                        case ABGR888:
                                fmt_cfg = 0;
-                               win->swap_rb = 1;
+                               swap_rb = 1;
                                break;
                        case RGB888:
                                fmt_cfg = 1;
-                               win->swap_rb = 0;
+                               swap_rb = 0;
                                break;
                        case RGB565:
                                fmt_cfg = 2;
-                               win->swap_rb = 0;               
+                               swap_rb = 0;
                                break;
                        default:
                                dev_err(lcdc_dev->driver.dev, 
@@ -2146,7 +2442,8 @@ static int win2_set_par(struct lcdc_device *lcdc_dev,
                                        __func__);
                                break;
                        }                       
-                       win->fmt_cfg = fmt_cfg;
+                       win->area[i].fmt_cfg = fmt_cfg;
+                       win->area[i].swap_rb = swap_rb;
                        win->area[i].dsp_stx = win->area[i].xpos + 
                                screen->mode.left_margin +
                                screen->mode.hsync_len;
@@ -2161,6 +2458,16 @@ static int win2_set_par(struct lcdc_device *lcdc_dev,
                                        screen->mode.upper_margin +
                                        screen->mode.vsync_len;
                        }
+                       if ((win->area[i].xact != win->area[i].xsize) ||
+                           (win->area[i].yact != win->area[i].ysize)) {
+                                pr_err("win[%d]->area[%d],not support scale\n",
+                                        win->id, i);
+                                pr_err("xact=%d,yact=%d,xsize=%d,ysize=%d\n",
+                                        win->area[i].xact,win->area[i].yact,
+                                        win->area[i].xsize,win->area[i].ysize);
+                                win->area[i].xsize = win->area[i].xact;
+                                win->area[i].ysize = win->area[i].yact;
+                       }
                }
        }
        rk3288_win_2_3_reg_update(&lcdc_dev->driver,2);
@@ -2173,28 +2480,28 @@ static int win3_set_par(struct lcdc_device *lcdc_dev,
 
 {
        int i;
-       u8 fmt_cfg;
+       u8 fmt_cfg, swap_rb;
 
        spin_lock(&lcdc_dev->reg_lock);
-       if(likely(lcdc_dev->clk_on)){
-               for(i=0;i<win->area_num;i++){
-                       switch (win->format){
+       if (likely(lcdc_dev->clk_on)) {
+               for (i = 0; i < win->area_num; i++) {
+                       switch (win->area[i].format) {
                        case ARGB888:
                                fmt_cfg = 0;
-                               win->swap_rb = 0;
+                               swap_rb = 0;
                                break;
                        case XBGR888:
                        case ABGR888:
                                fmt_cfg = 0;
-                               win->swap_rb = 1;
+                               swap_rb = 1;
                                break;
                        case RGB888:
                                fmt_cfg = 1;
-                               win->swap_rb = 0;
+                               swap_rb = 0;
                                break;
                        case RGB565:
                                fmt_cfg = 2;
-                               win->swap_rb = 0;               
+                               swap_rb = 0;
                                break;
                        default:
                                dev_err(lcdc_dev->driver.dev, 
@@ -2202,7 +2509,8 @@ static int win3_set_par(struct lcdc_device *lcdc_dev,
                                        __func__);
                                break;
                        }                       
-                       win->fmt_cfg = fmt_cfg;
+                       win->area[i].fmt_cfg = fmt_cfg;
+                       win->area[i].swap_rb = swap_rb;
                        win->area[i].dsp_stx = win->area[i].xpos + 
                                screen->mode.left_margin +
                                screen->mode.hsync_len;
@@ -2217,6 +2525,16 @@ static int win3_set_par(struct lcdc_device *lcdc_dev,
                                        screen->mode.upper_margin +
                                        screen->mode.vsync_len;
                        }
+                       if ((win->area[i].xact != win->area[i].xsize) ||
+                           (win->area[i].yact != win->area[i].ysize)) {
+                               pr_err("win[%d]->area[%d],not support scale\n",
+                                      win->id, i);
+                               pr_err("xact=%d,yact=%d,xsize=%d,ysize=%d\n",
+                                      win->area[i].xact, win->area[i].yact,
+                                      win->area[i].xsize, win->area[i].ysize);
+                               win->area[i].xsize = win->area[i].xact;
+                               win->area[i].ysize = win->area[i].yact;
+                       }
                }
        }
        rk3288_win_2_3_reg_update(&lcdc_dev->driver,3);
@@ -2335,9 +2653,6 @@ static int rk3288_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
-       int i, j;
-       int __iomem *c;
-       int v, r, g, b;
 
        if (!dev_drv->suspend_flag)
                return 0;
@@ -2349,27 +2664,7 @@ static int rk3288_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
                rk3288_lcdc_reg_restore(lcdc_dev);
 
                spin_lock(&lcdc_dev->reg_lock);
-               if (dev_drv->cur_screen->dsp_lut) {
-                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
-                                    v_DSP_LUT_EN(0));
-                       lcdc_cfg_done(lcdc_dev);
-                       mdelay(25);
-                       for (i = 0; i < 256; i++) {
-                               v = dev_drv->cur_screen->dsp_lut[i];
-                               c = lcdc_dev->dsp_lut_addr_base + (i << 2);
-                               b = (v & 0xff) << 2;
-                               g = (v & 0xff00) << 4;
-                               r = (v & 0xff0000) << 6;
-                               v = r + g + b;
-                               for (j = 0; j < 4; j++) {
-                                       writel_relaxed(v, c);
-                                       v += (1 + (1 << 10) + (1 << 20)) ;
-                                       c++;
-                               }
-                       }
-                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
-                                    v_DSP_LUT_EN(1));
-               }
+               rk3288_lcdc_set_lut(dev_drv);
 
                lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DSP_OUT_ZERO,
                             v_DSP_OUT_ZERO(0));
@@ -2413,9 +2708,65 @@ static int rk3288_lcdc_blank(struct rk_lcdc_driver *dev_drv,
        return 0;
 }
 
-static int rk3288_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv, int win_id)
+static int rk3288_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv,
+                                           int win_id, int area_id)
 {
-       return 0;
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+        u32 win_ctrl = 0;
+        u32 area_status = 0;
+
+        switch (win_id) {
+        case 0:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN0_CTRL0);
+                area_status = win_ctrl & m_WIN0_EN;
+                break;
+        case 1:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN1_CTRL0);
+                area_status = win_ctrl & m_WIN1_EN;
+                break;
+        case 2:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN2_CTRL0);
+                if (area_id == 0)
+                        area_status = win_ctrl & m_WIN2_MST0_EN;
+                if (area_id == 1)
+                        area_status = win_ctrl & m_WIN2_MST1_EN;
+                if (area_id == 2)
+                        area_status = win_ctrl & m_WIN2_MST2_EN;
+                if (area_id == 3)
+                        area_status = win_ctrl & m_WIN2_MST3_EN;
+                break;
+        case 3:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN3_CTRL0);
+                if (area_id == 0)
+                        area_status = win_ctrl & m_WIN3_MST0_EN;
+                if (area_id == 1)
+                        area_status = win_ctrl & m_WIN3_MST1_EN;
+                if (area_id == 2)
+                        area_status = win_ctrl & m_WIN3_MST2_EN;
+                if (area_id == 3)
+                        area_status = win_ctrl & m_WIN3_MST3_EN;
+                break;
+        case 4:
+                win_ctrl = lcdc_readl(lcdc_dev, HWC_CTRL0);
+                area_status = win_ctrl & m_HWC_EN;
+                break;
+        default:
+                pr_err("!!!%s,win[%d]area[%d],unsupport!!!\n",__func__,win_id,area_id);
+                break;
+        }
+       return area_status;
+}
+
+static int rk3288_lcdc_get_area_num(struct rk_lcdc_driver *dev_drv,
+                                          unsigned int *area_support)
+{
+        area_support[0] = 1;
+        area_support[1] = 1;
+        area_support[2] = 4;
+        area_support[3] = 4;
+
+        return 0;
 }
 
 /*overlay will be do at regupdate*/
@@ -2953,6 +3304,10 @@ static int rk3288_lcdc_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps,
        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 +
@@ -3054,6 +3409,8 @@ static int rk3288_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
        int i;
        unsigned int mask, val;
        struct rk_lcdc_win *win = NULL;
+       struct fb_info *fb0 = rk_get_fb(0);
+
        spin_lock(&lcdc_dev->reg_lock);
        lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
                             v_STANDBY_EN(lcdc_dev->standby));
@@ -3062,13 +3419,15 @@ static int rk3288_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
                if ((win->state == 0)&&(win->last_state == 1)) {
                        switch (win->id) {
                        case 0:
-                               lcdc_writel(lcdc_dev,WIN0_CTRL1,0x0);
+                               if (dev_drv->version == VOP_FULL_RK3288_V1_0)
+                                       lcdc_writel(lcdc_dev, WIN0_CTRL1, 0x0);
                                mask =  m_WIN0_EN;
                                val  =  v_WIN0_EN(0);
                                lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask,val);   
                                break;
                        case 1:
-                               lcdc_writel(lcdc_dev,WIN1_CTRL1,0x0);
+                               if (dev_drv->version == VOP_FULL_RK3288_V1_0)
+                                       lcdc_writel(lcdc_dev, WIN1_CTRL1, 0x0);
                                mask =  m_WIN1_EN;
                                val  =  v_WIN1_EN(0);
                                lcdc_msk_reg(lcdc_dev, WIN1_CTRL0, mask,val);           
@@ -3079,6 +3438,14 @@ static int rk3288_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
                                val  =  v_WIN2_EN(0) | v_WIN2_MST0_EN(0) | v_WIN2_MST1_EN(0) |
                                        v_WIN2_MST2_EN(0) | v_WIN2_MST3_EN(0);
                                lcdc_msk_reg(lcdc_dev, WIN2_CTRL0, mask,val);                   
+                               lcdc_writel(lcdc_dev,WIN2_DSP_INFO0,0);
+                               lcdc_writel(lcdc_dev,WIN2_DSP_INFO1,0);
+                               lcdc_writel(lcdc_dev,WIN2_DSP_INFO2,0);
+                               lcdc_writel(lcdc_dev,WIN2_DSP_INFO3,0);
+                               lcdc_writel(lcdc_dev,WIN2_MST0, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN2_MST1, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN2_MST2, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN2_MST3, fb0->fix.smem_start);
                                break;
                        case 3:
                                mask =  m_WIN3_EN | m_WIN3_MST0_EN | m_WIN3_MST1_EN |
@@ -3086,6 +3453,14 @@ static int rk3288_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
                                val  =  v_WIN3_EN(0) | v_WIN3_MST0_EN(0) |  v_WIN3_MST1_EN(0) |
                                        v_WIN3_MST2_EN(0) | v_WIN3_MST3_EN(0);
                                lcdc_msk_reg(lcdc_dev, WIN3_CTRL0, mask,val);
+                               lcdc_writel(lcdc_dev,WIN3_DSP_INFO0,0);
+                               lcdc_writel(lcdc_dev,WIN3_DSP_INFO1,0);
+                               lcdc_writel(lcdc_dev,WIN3_DSP_INFO2,0);
+                               lcdc_writel(lcdc_dev,WIN3_DSP_INFO3,0);
+                               lcdc_writel(lcdc_dev,WIN3_MST0, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN3_MST1, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN3_MST2, fb0->fix.smem_start);
+                               lcdc_writel(lcdc_dev,WIN3_MST3, fb0->fix.smem_start);
                                break;
                        default:
                                break;
@@ -3169,100 +3544,104 @@ int rk3288_lcdc_poll_vblank(struct rk_lcdc_driver *dev_drv)
 
        return ret;
 }
-static int rk3288_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,unsigned int *dsp_addr)
+
+static int rk3288_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
+                                   unsigned int dsp_addr[][4])
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        spin_lock(&lcdc_dev->reg_lock);
-       if(lcdc_dev->clk_on){
-               dsp_addr[0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
-               dsp_addr[1] = lcdc_readl(lcdc_dev, WIN1_YRGB_MST);
-               dsp_addr[2] = lcdc_readl(lcdc_dev, WIN2_MST0);
-               dsp_addr[3] = lcdc_readl(lcdc_dev, WIN3_MST0);
+       if (lcdc_dev->clk_on) {
+               dsp_addr[0][0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
+               dsp_addr[1][0] = lcdc_readl(lcdc_dev, WIN1_YRGB_MST);
+               dsp_addr[2][0] = lcdc_readl(lcdc_dev, WIN2_MST0);
+               dsp_addr[2][1] = lcdc_readl(lcdc_dev, WIN2_MST1);
+               dsp_addr[2][2] = lcdc_readl(lcdc_dev, WIN2_MST2);
+               dsp_addr[2][3] = lcdc_readl(lcdc_dev, WIN2_MST3);
+               dsp_addr[3][0] = lcdc_readl(lcdc_dev, WIN3_MST0);
+               dsp_addr[3][1] = lcdc_readl(lcdc_dev, WIN3_MST1);
+               dsp_addr[3][2] = lcdc_readl(lcdc_dev, WIN3_MST2);
+               dsp_addr[3][3] = lcdc_readl(lcdc_dev, WIN3_MST3);
        }
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
 }
 
-static struct lcdc_cabc_mode cabc_mode[4] = {
-/* pixel_num, stage_up, stage_down */
-       {5,     128,    0},     /*mode 1*/
-       {10,    128,    0},     /*mode 2*/
-       {15,    128,    0},     /*mode 3*/
-       {20,    128,    0},     /*mode 4*/
-};
-
-static int rk3288_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
+static int rk3288_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv,
+                                   int mode, int calc, int up,
+                                   int down, int global)
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        struct rk_screen *screen = dev_drv->cur_screen;
-       u32 total_pixel, calc_pixel, stage_up, stage_down, pixel_num;
-       u32 mask = 0, val = 0, cabc_en = 0;
-       u32 max_mode_num = sizeof(cabc_mode) / sizeof(struct lcdc_cabc_mode);
+       u32 total_pixel, calc_pixel, stage_up, stage_down;
+       u32 pixel_num, global_dn;
+       u32 mask = 0, val = 0;
 
-       dev_drv->cabc_mode = mode;
-
-       /* iomux connect to vop or pwm */
-       if (mode == 0) {
-               DBG(3, "close cabc and select rk pwm\n");
-               val = 0x30001;
-               writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_GPIO7A_IOMUX);
-               cabc_en = 0;
-       } else if (mode > 0 && mode <= max_mode_num) {
-               DBG(3, "open cabc and select vop pwm\n");
-               val = (dev_drv->id == 0) ? 0x30002 : 0x30003;
-               writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_GPIO7A_IOMUX);
-               cabc_en = 1;
-       } else if (mode > 0x10 && mode <= (max_mode_num + 0x10)) {
-               DBG(3, "open cabc and select rk pwm\n");
-               val = 0x30001;
-               writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_GPIO7A_IOMUX);
-               cabc_en = 1;
-               mode -= 0x10;
-       } else if (mode == 0xff) {
-               DBG(3, "close cabc and select vop pwm\n");
-               val = (dev_drv->id == 0) ? 0x30002 : 0x30003;
-               writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_GPIO7A_IOMUX);
-               cabc_en = 0;
-       } else {
-               dev_err(lcdc_dev->dev, "invalid cabc mode value:%d", mode);
+       if (dev_drv->version != VOP_FULL_RK3288_V1_1) {
+               pr_err("vop version:%x, not supoort cabc\n", dev_drv->version);
                return 0;
        }
-
-       if (cabc_en == 0) {
+       if (!screen->cabc_lut) {
+               pr_err("screen cabc lut not config, so not open cabc\n");
+               return 0;
+       }
+       dev_drv->cabc_mode = mode;
+       if (!dev_drv->cabc_mode) {
                spin_lock(&lcdc_dev->reg_lock);
-               if(lcdc_dev->clk_on) {
-                       lcdc_msk_reg(lcdc_dev, CABC_CTRL0, m_CABC_EN, v_CABC_EN(0));
+               if (lcdc_dev->clk_on) {
+                       lcdc_msk_reg(lcdc_dev, CABC_CTRL0,
+                                    m_CABC_HANDLE_EN | m_CABC_EN,
+                                    v_CABC_EN(0) | v_CABC_HANDLE_EN(0));
                        lcdc_cfg_done(lcdc_dev);
                }
+               pr_info("mode = 0, close cabc\n");
                spin_unlock(&lcdc_dev->reg_lock);
                return 0;
        }
 
        total_pixel = screen->mode.xres * screen->mode.yres;
-        pixel_num = 1000 - (cabc_mode[mode - 1].pixel_num);
+       pixel_num = 1000 - calc;
        calc_pixel = (total_pixel * pixel_num) / 1000;
-       stage_up = cabc_mode[mode - 1].stage_up;
-       stage_down = cabc_mode[mode - 1].stage_down;
-       
+       stage_up = up;
+       stage_down = down;
+       global_dn = global;
+       pr_info("enable cabc:mode=%d, calc=%d, up=%d, down=%d, global=%d\n",
+               mode, calc, stage_up, stage_down, global_dn);
+
        spin_lock(&lcdc_dev->reg_lock);
-       if(lcdc_dev->clk_on) {
-               mask = m_CABC_TOTAL_NUM | m_CABC_STAGE_DOWN;
-               val = v_CABC_TOTAL_NUM(total_pixel) | v_CABC_STAGE_DOWN(stage_down);
+       if (lcdc_dev->clk_on) {
+               mask = m_CABC_EN | m_CABC_HANDLE_EN | m_PWM_CONFIG_MODE |
+                       m_CABC_CALC_PIXEL_NUM;
+               val = v_CABC_EN(1) | v_CABC_HANDLE_EN(1) |
+                       v_PWM_CONFIG_MODE(STAGE_BY_STAGE) |
+                       v_CABC_CALC_PIXEL_NUM(calc_pixel);
+               lcdc_msk_reg(lcdc_dev, CABC_CTRL0, mask, val);
+
+               mask = m_CABC_LUT_EN | m_CABC_TOTAL_PIXEL_NUM;
+               val = v_CABC_LUT_EN(1) | v_CABC_TOTAL_PIXEL_NUM(total_pixel);
                lcdc_msk_reg(lcdc_dev, CABC_CTRL1, mask, val);
 
-               mask = m_CABC_EN | m_CABC_CALC_PIXEL_NUM |
-                       m_CABC_STAGE_UP;
-               val = v_CABC_EN(1) | v_CABC_CALC_PIXEL_NUM(calc_pixel) |
-                       v_CABC_STAGE_UP(stage_up);
-               lcdc_msk_reg(lcdc_dev, CABC_CTRL0, mask, val);
+               mask = m_CABC_STAGE_DOWN | m_CABC_STAGE_UP |
+                       m_CABC_STAGE_MODE | m_MAX_SCALE_CFG_VALUE |
+                       m_MAX_SCALE_CFG_ENABLE;
+               val = v_CABC_STAGE_DOWN(stage_down) |
+                       v_CABC_STAGE_UP(stage_up) |
+                       v_CABC_STAGE_MODE(0) | v_MAX_SCALE_CFG_VALUE(1) |
+                       v_MAX_SCALE_CFG_ENABLE(0);
+               lcdc_msk_reg(lcdc_dev, CABC_CTRL2, mask, val);
+
+               mask = m_CABC_GLOBAL_DN | m_CABC_GLOBAL_DN_LIMIT_EN;
+               val = v_CABC_GLOBAL_DN(global_dn) |
+                       v_CABC_GLOBAL_DN_LIMIT_EN(1);
+               lcdc_msk_reg(lcdc_dev, CABC_CTRL3, mask, val);
                lcdc_cfg_done(lcdc_dev);
        }
        spin_unlock(&lcdc_dev->reg_lock);
 
        return 0;
 }
+
 /*
        a:[-30~0]:
            sin_hue = sin(a)*256 +0x100;
@@ -3402,11 +3781,15 @@ static int rk3288_lcdc_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open)
                        lcdc_writel(lcdc_dev,BCSH_COLOR_BAR,0x1);
                        lcdc_writel(lcdc_dev,BCSH_BCS,0xd0010000);
                        lcdc_writel(lcdc_dev,BCSH_H,0x01000000);
+                       dev_drv->bcsh.enable = 1;
                } else {
                        mask = m_BCSH_EN;
                        val = v_BCSH_EN(0);
                        lcdc_msk_reg(lcdc_dev, BCSH_COLOR_BAR, mask, val);
+                       dev_drv->bcsh.enable = 0;
                }
+               if (dev_drv->version == VOP_FULL_RK3288_V1_1)
+                       rk3288_lcdc_bcsh_path_sel(dev_drv);
                lcdc_cfg_done(lcdc_dev);
        }
        spin_unlock(&lcdc_dev->reg_lock);
@@ -3444,6 +3827,21 @@ static int rk3288_lcdc_set_bcsh(struct rk_lcdc_driver *dev_drv,
        return 0;
 }
 
+static int rk3288_lcdc_set_overscan(struct rk_lcdc_driver *dev_drv,
+                                   struct overscan *overscan)
+{
+       struct lcdc_device *lcdc_dev =
+               container_of(dev_drv, struct lcdc_device, driver);
+
+       if (unlikely(!lcdc_dev->clk_on)) {
+               pr_info("%s,clk_on = %d\n", __func__, lcdc_dev->clk_on);
+               return 0;
+       }
+       rk3288_lcdc_post_cfg(dev_drv);
+
+       return 0;
+}
+
 static struct rk_lcdc_win lcdc_win[] = {
        [0] = {
               .name = "win0",
@@ -3471,6 +3869,8 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .open                   = rk3288_lcdc_open,
        .win_direct_en          = rk3288_lcdc_win_direct_en,
        .load_screen            = rk3288_load_screen,
+       .get_dspbuf_info        = rk3288_get_dspbuf_info,
+       .post_dspbuf            = rk3288_post_dspbuf,
        .set_par                = rk3288_lcdc_set_par,
        .pan_display            = rk3288_lcdc_pan_display,
        .direct_set_addr        = rk3288_lcdc_direct_set_win_addr,
@@ -3480,6 +3880,7 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .suspend                = rk3288_lcdc_early_suspend,
        .resume                 = rk3288_lcdc_early_resume,
        .get_win_state          = rk3288_lcdc_get_win_state,
+       .area_support_num = rk3288_lcdc_get_area_num,
        .ovl_mgr                = rk3288_lcdc_ovl_mgr,
        .get_disp_info          = rk3288_lcdc_get_disp_info,
        .fps_mgr                = rk3288_lcdc_fps_mgr,
@@ -3491,7 +3892,7 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .dpi_win_sel            = rk3288_lcdc_dpi_win_sel,
        .dpi_status             = rk3288_lcdc_dpi_status,
        .get_dsp_addr           = rk3288_lcdc_get_dsp_addr,
-       .set_dsp_cabc           = rk3288_lcdc_set_dsp_cabc,
+       .set_dsp_cabc           = rk3288_lcdc_set_dsp_cabc,
        .set_dsp_bcsh_hue       = rk3288_lcdc_set_bcsh_hue,
        .set_dsp_bcsh_bcs       = rk3288_lcdc_set_bcsh_bcs,
        .get_dsp_bcsh_hue       = rk3288_lcdc_get_bcsh_hue,
@@ -3500,6 +3901,9 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .dump_reg               = rk3288_lcdc_reg_dump,
        .cfg_done               = rk3288_lcdc_config_done,
        .set_irq_to_cpu         = rk3288_lcdc_set_irq_to_cpu,
+       .mmu_en    = rk3288_lcdc_mmu_en,
+       .set_overscan           = rk3288_lcdc_set_overscan,
+
 };
 
 #ifdef LCDC_IRQ_DEBUG
@@ -3558,9 +3962,6 @@ static irqreturn_t rk3288_lcdc_isr(int irq, void *dev_id)
                        complete(&(lcdc_dev->driver.frame_done));
                        spin_unlock(&(lcdc_dev->driver.cpl_lock));
                }
-#ifdef CONFIG_DRM_ROCKCHIP
-               lcdc_dev->driver.irq_call_back(&lcdc_dev->driver);
-#endif 
                lcdc_dev->driver.vsync_info.timestamp = timestamp;
                wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
 
@@ -3660,14 +4061,16 @@ static int rk3288_lcdc_parse_dt(struct lcdc_device *lcdc_dev)
                dev_drv->bcsh.cos_hue = (val >> 8) & 0xff;
        }
 
-#if defined(CONFIG_ROCKCHIP_IOMMU)
        if (of_property_read_u32(np, "rockchip,iommu-enabled", &val))
                dev_drv->iommu_enabled = 0;
        else
                dev_drv->iommu_enabled = val;
-#else
-       dev_drv->iommu_enabled = 0;
-#endif
+
+       if (of_property_read_u32(np, "rockchip,dsp_mode", &val))
+               dev_drv->dsp_mode = DEFAULT_MODE;
+       else
+               dev_drv->dsp_mode = val;
+
        return 0;
 }