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 053cca4f7dd9b8a1b93cc9be3db48e718e270d70..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;                                                       \
 }
@@ -289,9 +308,13 @@ static void lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev)
        struct rk_lcdc_win *win0 = lcdc_dev->driver.win[0];
 
        spin_lock(&lcdc_dev->reg_lock);
+       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;
@@ -341,6 +364,22 @@ static void lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev)
                        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;
                }
@@ -371,8 +410,8 @@ 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*/
@@ -405,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;
 
 
@@ -444,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 +
@@ -762,7 +808,8 @@ 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){
@@ -848,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);
@@ -880,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){
@@ -904,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){
@@ -928,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){
@@ -952,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)
@@ -1015,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)
@@ -1026,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 =
@@ -1064,8 +1131,33 @@ 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)
+                                 u16 *yact, int *format, u32 *dsp_addr,
+                                 int *ymirror)
 {
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                                    struct lcdc_device, driver);
@@ -1087,11 +1179,13 @@ static int rk3288_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact,
 }
 
 static int rk3288_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
-                             int format, u16 xact, u16 yact, u16 xvir)
+                             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;
@@ -1106,6 +1200,8 @@ static int rk3288_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
        lcdc_writel(lcdc_dev, WIN0_YRGB_MST, rgb_mst);
 
        lcdc_cfg_done(lcdc_dev);
+       win->state = 1;
+       win->last_state = 1;
 
        return 0;
 }
@@ -1113,6 +1209,7 @@ static int rk3288_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
 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);
@@ -1127,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;
@@ -1142,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:
@@ -1184,24 +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:                  
-                       mask = m_RGB_OUT_EN;
-                       val = v_RGB_OUT_EN(1);
-                       v = 1 << (3+16);
-                       v |= (lcdc_dev->id << 3);
-                       break;
+               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);
-                       face = OUT_RGB_AAA;  /*RGB AAA output*/
                        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;
@@ -1212,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);
@@ -1228,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) |
@@ -1237,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;
@@ -1263,16 +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);
+       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*/
@@ -1382,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 |
@@ -1418,7 +1575,6 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                rk3288_lcdc_pre_init(dev_drv);
                rk3288_lcdc_clk_enable(lcdc_dev);
                rk3288_lcdc_enable_irq(dev_drv);
-#if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (!dev_drv->mmu_dev) {
                                dev_drv->mmu_dev =
@@ -1432,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);
        }
 
@@ -1468,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);
        }
@@ -1540,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;
@@ -1562,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;
@@ -2357,16 +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;
+                       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);
@@ -2485,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;
@@ -2499,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));
@@ -2563,25 +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)
+{
+       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)
 {
-        struct lcdc_device *lcdc_dev =
-                container_of(dev_drv, struct lcdc_device, driver);
-        int win_status = 0;
-        if (win_id == 0)
-                win_status = lcdc_read_bit(lcdc_dev, WIN0_CTRL0, m_WIN0_EN);
-        else if (win_id == 1)
-                win_status = lcdc_read_bit(lcdc_dev, WIN1_CTRL0, m_WIN1_EN);
-        else if (win_id == 2)
-                win_status = lcdc_read_bit(lcdc_dev, WIN2_CTRL0, m_WIN2_EN);
-        else if (win_id == 3)
-                win_status = lcdc_read_bit(lcdc_dev, WIN3_CTRL0, m_WIN3_EN);
-        else if (win_id == 4)
-                win_status = lcdc_read_bit(lcdc_dev, HWC_CTRL0, m_HWC_EN);
-        else
-                pr_err("!!!%s,win_id :%d,unsupport!!!\n",__func__,win_id);
+        area_support[0] = 1;
+        area_support[1] = 1;
+        area_support[2] = 4;
+        area_support[3] = 4;
 
-        return win_status;
+        return 0;
 }
 
 /*overlay will be do at regupdate*/
@@ -3224,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));
@@ -3232,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);           
@@ -3249,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 |
@@ -3256,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;
@@ -3339,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;
@@ -3572,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);
@@ -3614,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",
@@ -3652,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,
@@ -3663,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,
@@ -3672,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
@@ -3730,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);
 
@@ -3832,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;
 }