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 bdc75e36a26b2dc7dc9c6be140258d28ea53ff48..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;
 
@@ -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;
                }
@@ -769,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){
@@ -855,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);
@@ -887,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){
@@ -911,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){
@@ -935,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){
@@ -959,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)
@@ -1035,7 +1085,6 @@ static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
                pr_info("%s,clk_on = %d\n", __func__, lcdc_dev->clk_on);
                return 0;
        }
-#if defined(CONFIG_ROCKCHIP_IOMMU)
        if (dev_drv->iommu_enabled) {
                if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) {
 
@@ -1053,7 +1102,6 @@ static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
                        rockchip_iovmm_activate(dev_drv->dev);
                }
        }
-#endif
        return 0;
 }
 
@@ -1083,8 +1131,33 @@ static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv, int reset_rate)
 
 }
 
+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);
@@ -1106,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;
@@ -1125,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;
 }
@@ -1132,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);
@@ -1146,6 +1224,9 @@ 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;
@@ -1210,6 +1291,26 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                            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 |
@@ -1234,7 +1335,9 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        v |= (lcdc_dev->id << 3);
                        break;
                case SCREEN_HDMI:
-                       face = OUT_P101010;/*RGB 101010 output*/
+                       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);
                        break;
@@ -1251,6 +1354,15 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        mask = m_EDP_OUT_EN;
                        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
@@ -1260,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) |
@@ -1269,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;
@@ -1298,6 +1413,16 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                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, 1);
@@ -1307,7 +1432,7 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
        if (screen->init)
                screen->init();
        
-       return 0;
+       return ret;
 }
 
 /*enable layer,open:1,enable;0 disable*/
@@ -1450,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 =
@@ -1465,7 +1589,6 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                                }
                        }
                }
-#endif
                rk3288_lcdc_reg_restore(lcdc_dev);
                /*if (dev_drv->iommu_enabled)
                   rk3368_lcdc_mmu_en(dev_drv); */
@@ -1478,8 +1601,7 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                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);
        }
 
@@ -1498,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);
        }
@@ -1570,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;
@@ -1592,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;
@@ -2387,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);
@@ -2515,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;
@@ -2529,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));
@@ -3294,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));
@@ -3302,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);           
@@ -3319,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 |
@@ -3326,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;
@@ -3432,86 +3567,81 @@ static int rk3288_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
        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 __maybe_unused
-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);
-
-       dev_drv->cabc_mode = mode;
+       u32 total_pixel, calc_pixel, stage_up, stage_down;
+       u32 pixel_num, global_dn;
+       u32 mask = 0, val = 0;
 
-       /* 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;
@@ -3651,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);
@@ -3758,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,
@@ -3828,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);
 
@@ -3930,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;
 }