Merge branch develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / lcdc / rk3368_lcdc.c
old mode 100644 (file)
new mode 100755 (executable)
index 2340d65..151ee94
@@ -40,7 +40,7 @@
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
 #endif
-#define CONFIG_RK_FPGA 1
+/*#define CONFIG_RK_FPGA 1*/
 
 static int dbg_thresd;
 module_param(dbg_thresd, int, S_IRUGO | S_IWUSR);
@@ -95,30 +95,49 @@ u32 rk3368_get_hard_ware_vskiplines(u32 srch, u32 dsth)
        return vscalednmult;
 }
 
-static int rk3368_lcdc_set_lut(struct rk_lcdc_driver *dev_drv)
+
+static int rk3368_set_cabc_lut(struct rk_lcdc_driver *dev_drv, int *cabc_lut)
 {
-       int i, j;
+       int i;
        int __iomem *c;
-       u32 v, r, g, b;
+       u32 v;
        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));
+
+       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++;
-               }
+               v = cabc_lut[i];
+               c = lcdc_dev->cabc_lut_addr_base + i;
+               writel_relaxed(v, c);
        }
-       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN, v_DSP_LUT_EN(1));
+       lcdc_msk_reg(lcdc_dev, CABC_CTRL1, m_CABC_LUT_EN,
+                    v_CABC_LUT_EN(1));
+       return 0;
+}
+
+
+static int rk3368_lcdc_set_lut(struct rk_lcdc_driver *dev_drv, int *dsp_lut)
+{
+       int i;
+       int __iomem *c;
+       u32 v;
+       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));
+       lcdc_cfg_done(lcdc_dev);
+       mdelay(25);
+       for (i = 0; i < 256; i++) {
+               v = dsp_lut[i];
+               c = lcdc_dev->dsp_lut_addr_base + i;
+               writel_relaxed(v, c);
+       }
+       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                    v_DSP_LUT_EN(1));
 
        return 0;
 }
@@ -133,7 +152,7 @@ static int rk3368_lcdc_clk_enable(struct lcdc_device *lcdc_dev)
                clk_prepare_enable(lcdc_dev->hclk);
                clk_prepare_enable(lcdc_dev->dclk);
                clk_prepare_enable(lcdc_dev->aclk);
-               clk_prepare_enable(lcdc_dev->pd);
+               /*clk_prepare_enable(lcdc_dev->pd);*/
                spin_lock(&lcdc_dev->reg_lock);
                lcdc_dev->clk_on = 1;
                spin_unlock(&lcdc_dev->reg_lock);
@@ -156,13 +175,14 @@ static int rk3368_lcdc_clk_disable(struct lcdc_device *lcdc_dev)
                clk_disable_unprepare(lcdc_dev->dclk);
                clk_disable_unprepare(lcdc_dev->hclk);
                clk_disable_unprepare(lcdc_dev->aclk);
-               clk_disable_unprepare(lcdc_dev->pd);
+               /*clk_disable_unprepare(lcdc_dev->pd);*/
        }
 
        return 0;
 }
 
-static int rk3368_lcdc_disable_irq(struct lcdc_device *lcdc_dev)
+static int __maybe_unused
+       rk3368_lcdc_disable_irq(struct lcdc_device *lcdc_dev)
 {
        u32 mask, val;
 
@@ -330,8 +350,8 @@ 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);
-       for (reg = 0; reg < FRC_LOWER11_1; reg += 4) {
-               val = lcdc_readl(lcdc_dev, reg);
+       for (reg = 0; reg < SCAN_LINE_NUM; reg += 4) {
+               val = lcdc_readl_backup(lcdc_dev, reg);
                switch (reg) {
                case WIN0_ACT_INFO:
                        win0->area[0].xact = (val & m_WIN0_ACT_WIDTH) + 1;
@@ -387,7 +407,7 @@ static void lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev)
 /********do basic init*********/
 static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 {
-       u32 mask, val;
+       u32 mask, val, v;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        if (lcdc_dev->pre_init)
@@ -396,10 +416,9 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
        lcdc_dev->hclk = devm_clk_get(lcdc_dev->dev, "hclk_lcdc");
        lcdc_dev->aclk = devm_clk_get(lcdc_dev->dev, "aclk_lcdc");
        lcdc_dev->dclk = devm_clk_get(lcdc_dev->dev, "dclk_lcdc");
-       lcdc_dev->pll_sclk = devm_clk_get(lcdc_dev->dev, "sclk_pll");
-       lcdc_dev->pd = devm_clk_get(lcdc_dev->dev, "pd_lcdc");
+       /*lcdc_dev->pd = devm_clk_get(lcdc_dev->dev, "pd_lcdc");*/
 
-       if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||
+       if (/*IS_ERR(lcdc_dev->pd) || */(IS_ERR(lcdc_dev->aclk)) ||
            (IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) {
                dev_err(lcdc_dev->dev, "failed to get lcdc%d clk source\n",
                        lcdc_dev->id);
@@ -410,6 +429,15 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 
        /*backup reg config at uboot */
        lcdc_read_reg_defalut_cfg(lcdc_dev);
+       if (lcdc_dev->pwr18 == 1) {
+               v = 0x00200020; /*bit5: 1,1.8v;0,3.3v*/
+               lcdc_grf_writel(lcdc_dev->pmugrf_base,
+                               PMUGRF_SOC_CON0_VOP, v);
+       } else {
+               v = 0x00200000; /*bit5: 1,1.8v;0,3.3v*/
+               lcdc_grf_writel(lcdc_dev->pmugrf_base,
+                               PMUGRF_SOC_CON0_VOP, v);
+       }
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_0, 0x15110903);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_1, 0x00030911);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_0, 0x1a150b04);
@@ -426,6 +454,7 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 
        mask = m_AUTO_GATING_EN;
        val = v_AUTO_GATING_EN(0);
+       lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
        lcdc_cfg_done(lcdc_dev);
        /*disable win0 to workaround iommu pagefault */
        /*if (dev_drv->iommu_enabled) */
@@ -437,17 +466,6 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 
 static void rk3368_lcdc_deint(struct lcdc_device *lcdc_dev)
 {
-       rk3368_lcdc_disable_irq(lcdc_dev);
-       spin_lock(&lcdc_dev->reg_lock);
-       if (likely(lcdc_dev->clk_on)) {
-               lcdc_dev->clk_on = 0;
-               lcdc_set_bit(lcdc_dev, SYS_CTRL, m_STANDBY_EN);
-               lcdc_cfg_done(lcdc_dev);
-               spin_unlock(&lcdc_dev->reg_lock);
-       } else {
-               spin_unlock(&lcdc_dev->reg_lock);
-       }
-       mdelay(1);
 }
 
 static int rk3368_lcdc_post_cfg(struct rk_lcdc_driver *dev_drv)
@@ -465,6 +483,13 @@ static int rk3368_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 +
@@ -499,15 +524,6 @@ static int rk3368_lcdc_post_cfg(struct rk_lcdc_driver *dev_drv)
                screen->post_dsp_sty = y_res - screen->post_ysize;
        }
 
-       if (screen->y_mirror == 0) {
-               post_dsp_vact_st = screen->post_dsp_sty +
-                   screen->mode.vsync_len + screen->mode.upper_margin;
-               post_dsp_vact_end = post_dsp_vact_st + screen->post_ysize;
-       } else {
-               post_dsp_vact_end = v_total - screen->mode.lower_margin -
-                   screen->post_dsp_sty;
-               post_dsp_vact_st = post_dsp_vact_end - screen->post_ysize;
-       }
        if ((screen->post_ysize < y_res) && (screen->post_ysize != 0)) {
                post_vsd_en = 1;
                post_v_fac = GET_SCALE_FACTOR_BILI_DN(y_res,
@@ -517,10 +533,37 @@ static int rk3368_lcdc_post_cfg(struct rk_lcdc_driver *dev_drv)
                post_v_fac = 0x1000;
        }
 
-       if (screen->interlace == 1) {
-               post_dsp_vact_st_f1 = v_total + post_dsp_vact_st;
-               post_dsp_vact_end_f1 = post_dsp_vact_st_f1 + screen->post_ysize;
+       if (screen->mode.vmode == FB_VMODE_INTERLACED) {
+               post_dsp_vact_st = screen->post_dsp_sty / 2 +
+                                       screen->mode.vsync_len +
+                                       screen->mode.upper_margin;
+               post_dsp_vact_end = post_dsp_vact_st +
+                                       screen->post_ysize / 2;
+
+               post_dsp_vact_st_f1 = screen->mode.vsync_len +
+                                     screen->mode.upper_margin +
+                                     y_res/2 +
+                                     screen->mode.lower_margin +
+                                     screen->mode.vsync_len +
+                                     screen->mode.upper_margin +
+                                     screen->post_dsp_sty / 2 +
+                                     1;
+               post_dsp_vact_end_f1 = post_dsp_vact_st_f1 +
+                                       screen->post_ysize/2;
        } else {
+               if (screen->y_mirror == 0) {
+                       post_dsp_vact_st = screen->post_dsp_sty +
+                           screen->mode.vsync_len +
+                           screen->mode.upper_margin;
+                       post_dsp_vact_end = post_dsp_vact_st +
+                               screen->post_ysize;
+               } else {
+                       post_dsp_vact_end = v_total -
+                               screen->mode.lower_margin -
+                           screen->post_dsp_sty;
+                       post_dsp_vact_st = post_dsp_vact_end -
+                               screen->post_ysize;
+               }
                post_dsp_vact_st_f1 = 0;
                post_dsp_vact_end_f1 = 0;
        }
@@ -604,6 +647,8 @@ static int rk3368_lcdc_alpha_cfg(struct rk_lcdc_driver *dev_drv, int win_id)
 
        for (i = 0; i < win->area_num; i++) {
                ppixel_alpha |= ((win->area[i].format == ARGB888) ||
+                                (win->area[i].format == FBDC_ARGB_888) ||
+                                (win->area[i].format == FBDC_ABGR_888) ||
                                 (win->area[i].format == ABGR888)) ? 1 : 0;
        }
        global_alpha = (win->g_alpha_val == 0) ? 0 : 1;
@@ -756,7 +801,8 @@ static int rk3368_lcdc_area_xst(struct rk_lcdc_win *win, int area_num)
        return 0;
 }
 
-static int rk3368_lcdc_area_swap(struct rk_lcdc_win *win, int area_num)
+static int __maybe_unused
+       rk3368_lcdc_area_swap(struct rk_lcdc_win *win, int area_num)
 {
        struct rk_lcdc_win_area area_temp;
 
@@ -787,9 +833,10 @@ static int rk3368_lcdc_area_swap(struct rk_lcdc_win *win, int area_num)
        return 0;
 }
 
-static int rk3368_win_area_check_var(int win_id, int area_num,
-                                    struct rk_lcdc_win_area *area_pre,
-                                    struct rk_lcdc_win_area *area_now)
+static int __maybe_unused
+rk3368_win_area_check_var(int win_id, int area_num,
+                         struct rk_lcdc_win_area *area_pre,
+                         struct rk_lcdc_win_area *area_now)
 {
        if ((area_pre->xpos > area_now->xpos) ||
            ((area_pre->xpos + area_pre->xsize > area_now->xpos) &&
@@ -847,10 +894,6 @@ static int rk3368_fbdc_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
        val = v_IFBDC_TILES_NUM(win->area[0].fbdc_num_tiles);
        lcdc_msk_reg(lcdc_dev, IFBDC_TILES_NUM, mask, val);
 
-       mask = m_IFBDC_BASE_ADDR;
-       val = v_IFBDC_BASE_ADDR(win->area[0].y_addr);
-       lcdc_msk_reg(lcdc_dev, IFBDC_BASE_ADDR, mask, val);
-
        mask = m_IFBDC_MB_SIZE_WIDTH | m_IFBDC_MB_SIZE_HEIGHT;
        val = v_IFBDC_MB_SIZE_WIDTH(win->area[0].fbdc_mb_width) |
            v_IFBDC_MB_SIZE_HEIGHT(win->area[0].fbdc_mb_height);
@@ -895,6 +938,7 @@ static int rk3368_init_fbdc_config(struct rk_lcdc_driver *dev_drv, int win_id)
                mb_w_size = 16;
                break;
        case VOP_FORMAT_RGB565:
+               fbdc_dsp_width_ratio = 1;
                mb_w_size = 32;
                break;
        default:
@@ -974,7 +1018,6 @@ static int rk3368_init_fbdc_config(struct rk_lcdc_driver *dev_drv, int win_id)
                    (fbdc_mb_yst * fbdc_mb_vir_width) + fbdc_mb_xst;
        }
        /*fbdc fmt maybe need to change*/
-       win->area[0].fbdc_fmt_cfg = win->area[0].fbdc_data_format;
        win->area[0].fbdc_dsp_width_ratio = fbdc_dsp_width_ratio;
        win->area[0].fbdc_mb_vir_width = fbdc_mb_vir_width;
        win->area[0].fbdc_mb_vir_height = fbdc_mb_vir_height;
@@ -1035,11 +1078,16 @@ static int rk3368_win_0_1_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
 
        if (win->state == 1) {
                rk3368_lcdc_csc_mode(lcdc_dev, win);
-               if (win->area[0].fbdc_en)
+               if (win->area[0].fbdc_en) {
                        rk3368_fbdc_reg_update(&lcdc_dev->driver, win_id);
+               } else {
+                       mask = m_IFBDC_CTRL_FBDC_EN;
+                       val = v_IFBDC_CTRL_FBDC_EN(0);
+                       lcdc_msk_reg(lcdc_dev, IFBDC_CTRL, mask, val);
+               }
                mask = m_WIN0_EN | m_WIN0_DATA_FMT | m_WIN0_FMT_10 |
                    m_WIN0_LB_MODE | m_WIN0_RB_SWAP | m_WIN0_X_MIRROR |
-                   m_WIN0_Y_MIRROR | m_WIN0_CSC_MODE;
+                   m_WIN0_Y_MIRROR | m_WIN0_CSC_MODE |m_WIN0_UV_SWAP;
                val = v_WIN0_EN(win->state) |
                    v_WIN0_DATA_FMT(win->area[0].fmt_cfg) |
                    v_WIN0_FMT_10(win->fmt_10) |
@@ -1047,7 +1095,8 @@ static int rk3368_win_0_1_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
                    v_WIN0_RB_SWAP(win->area[0].swap_rb) |
                    v_WIN0_X_MIRROR(win->mirror_en) |
                    v_WIN0_Y_MIRROR(win->mirror_en) |
-                   v_WIN0_CSC_MODE(win->csc_mode);
+                   v_WIN0_CSC_MODE(win->csc_mode) |
+                   v_WIN0_UV_SWAP(win->area[0].swap_uv);
                lcdc_msk_reg(lcdc_dev, WIN0_CTRL0 + off, mask, val);
 
                mask = m_WIN0_BIC_COE_SEL |
@@ -1121,20 +1170,20 @@ static int rk3368_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        struct rk_lcdc_win *win = dev_drv->win[win_id];
-       struct rk_screen *screen = dev_drv->cur_screen;
        unsigned int mask, val, off;
 
        off = (win_id - 2) * 0x50;
        rk3368_lcdc_area_xst(win, win->area_num);
-       if (((screen->y_mirror == 1) || (win->mirror_en)) &&
-           (win->area_num > 1)) {
-               rk3368_lcdc_area_swap(win, win->area_num);
-       }
 
        if (win->state == 1) {
                rk3368_lcdc_csc_mode(lcdc_dev, win);
-               if (win->area[0].fbdc_en)
+               if (win->area[0].fbdc_en) {
                        rk3368_fbdc_reg_update(&lcdc_dev->driver, win_id);
+               } else {
+                       mask = m_IFBDC_CTRL_FBDC_EN;
+                       val = v_IFBDC_CTRL_FBDC_EN(0);
+                       lcdc_msk_reg(lcdc_dev, IFBDC_CTRL, mask, val);
+               }
 
                mask = m_WIN2_EN | m_WIN2_CSC_MODE;
                val = v_WIN2_EN(1) | v_WIN1_CSC_MODE(win->csc_mode);
@@ -1167,14 +1216,15 @@ static int rk3368_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
                }
                /*area 1 */
                if (win->area[1].state == 1) {
-                       rk3368_win_area_check_var(win_id, 1,
+                       /*rk3368_win_area_check_var(win_id, 1,
                                                  &win->area[0], &win->area[1]);
+                       */
 
                        mask = m_WIN2_MST1_EN | m_WIN2_DATA_FMT1 |
                            m_WIN2_RB_SWAP1;
                        val = v_WIN2_MST1_EN(win->area[1].state) |
-                           v_WIN2_DATA_FMT0(win->area[1].fmt_cfg) |
-                           v_WIN2_RB_SWAP0(win->area[1].swap_rb);
+                           v_WIN2_DATA_FMT1(win->area[1].fmt_cfg) |
+                           v_WIN2_RB_SWAP1(win->area[1].swap_rb);
                        lcdc_msk_reg(lcdc_dev, WIN2_CTRL0 + off, mask, val);
 
                        mask = m_WIN2_VIR_STRIDE1;
@@ -1196,14 +1246,15 @@ static int rk3368_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
                }
                /*area 2 */
                if (win->area[2].state == 1) {
-                       rk3368_win_area_check_var(win_id, 2,
+                       /*rk3368_win_area_check_var(win_id, 2,
                                                  &win->area[1], &win->area[2]);
+                       */
 
                        mask = m_WIN2_MST2_EN | m_WIN2_DATA_FMT2 |
                            m_WIN2_RB_SWAP2;
                        val = v_WIN2_MST2_EN(win->area[2].state) |
-                           v_WIN2_DATA_FMT0(win->area[2].fmt_cfg) |
-                           v_WIN2_RB_SWAP0(win->area[2].swap_rb);
+                           v_WIN2_DATA_FMT2(win->area[2].fmt_cfg) |
+                           v_WIN2_RB_SWAP2(win->area[2].swap_rb);
                        lcdc_msk_reg(lcdc_dev, WIN2_CTRL0 + off, mask, val);
 
                        mask = m_WIN2_VIR_STRIDE2;
@@ -1225,14 +1276,15 @@ static int rk3368_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
                }
                /*area 3 */
                if (win->area[3].state == 1) {
-                       rk3368_win_area_check_var(win_id, 3,
+                       /*rk3368_win_area_check_var(win_id, 3,
                                                  &win->area[2], &win->area[3]);
+                       */
 
                        mask = m_WIN2_MST3_EN | m_WIN2_DATA_FMT3 |
                            m_WIN2_RB_SWAP3;
                        val = v_WIN2_MST3_EN(win->area[3].state) |
-                           v_WIN2_DATA_FMT0(win->area[3].fmt_cfg) |
-                           v_WIN2_RB_SWAP0(win->area[3].swap_rb);
+                           v_WIN2_DATA_FMT3(win->area[3].fmt_cfg) |
+                           v_WIN2_RB_SWAP3(win->area[3].swap_rb);
                        lcdc_msk_reg(lcdc_dev, WIN2_CTRL0 + off, mask, val);
 
                        mask = m_WIN2_VIR_STRIDE3;
@@ -1368,10 +1420,7 @@ static int rk3368_lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
 
 static int rk3368_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, 0x260);
+       memcpy((u8 *)lcdc_dev->regs, (u8 *)lcdc_dev->regsbak, 0x270);
        return 0;
 }
 
@@ -1380,30 +1429,29 @@ static int __maybe_unused rk3368_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);
-       }
-       /*spin_unlock(&lcdc_dev->reg_lock); */
+
 #if defined(CONFIG_ROCKCHIP_IOMMU)
        if (dev_drv->iommu_enabled) {
                if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) {
+                       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);
+                       }
                        lcdc_dev->iommu_status = 1;
                        rockchip_iovmm_activate(dev_drv->dev);
-                       rk312x_lcdc_mmu_en(dev_drv);
                }
        }
 #endif
        return 0;
 }
 
-static int rk3368_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
+static int rk3368_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv, int reset_rate)
 {
        int ret = 0, fps = 0;
        struct lcdc_device *lcdc_dev =
@@ -1412,13 +1460,8 @@ static int rk3368_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
 #ifdef CONFIG_RK_FPGA
        return 0;
 #endif
-       /*set pll */
-       ret = clk_set_rate(lcdc_dev->pll_sclk, screen->mode.pixclock);
-       if (ret)
-               dev_err(dev_drv->dev, "set lcdc%d pll_sclk failed\n",
-                       lcdc_dev->id);
-
-       ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock);/*set pll */
+        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 =
@@ -1452,13 +1495,6 @@ static int rk3368_config_timing(struct rk_lcdc_driver *dev_drv)
        h_total = hsync_len + left_margin + x_res + right_margin;
        v_total = vsync_len + upper_margin + y_res + lower_margin;
 
-       screen->post_dsp_stx = x_res * (100 - screen->overscan.left) / 200;
-       screen->post_dsp_sty = y_res * (100 - screen->overscan.top) / 200;
-       screen->post_xsize = x_res *
-           (screen->overscan.left + screen->overscan.right) / 200;
-       screen->post_ysize = y_res *
-           (screen->overscan.top + screen->overscan.bottom) / 200;
-
        mask = m_DSP_HS_PW | m_DSP_HTOTAL;
        val = v_DSP_HS_PW(hsync_len) | v_DSP_HTOTAL(h_total);
        lcdc_msk_reg(lcdc_dev, DSP_HTOTAL_HS_END, mask, val);
@@ -1530,9 +1566,10 @@ static int rk3368_config_timing(struct rk_lcdc_driver *dev_drv)
                val = v_HWC_INTERLACE_READ(1);
                lcdc_msk_reg(lcdc_dev, HWC_CTRL0, mask, val);
 
-               mask = m_DSP_LINE_FLAG0_NUM;
+               mask = m_DSP_LINE_FLAG0_NUM | m_DSP_LINE_FLAG1_NUM;
                val =
-                   v_DSP_LINE_FLAG0_NUM(vsync_len + upper_margin + y_res / 2);
+                   v_DSP_LINE_FLAG0_NUM(vsync_len + upper_margin + y_res / 2) |
+                   v_DSP_LINE_FLAG1_NUM(vsync_len + upper_margin + y_res / 2);
                lcdc_msk_reg(lcdc_dev, LINE_FLAG, mask, val);
        } else {
                mask = m_DSP_VS_PW | m_DSP_VTOTAL;
@@ -1576,8 +1613,9 @@ static int rk3368_config_timing(struct rk_lcdc_driver *dev_drv)
                val = v_HWC_INTERLACE_READ(0);
                lcdc_msk_reg(lcdc_dev, HWC_CTRL0, mask, val);
 
-               mask = m_DSP_LINE_FLAG0_NUM;
-               val = v_DSP_LINE_FLAG0_NUM(vsync_len + upper_margin + y_res);
+               mask = m_DSP_LINE_FLAG0_NUM | m_DSP_LINE_FLAG1_NUM;
+               val = v_DSP_LINE_FLAG0_NUM(vsync_len + upper_margin + y_res) |
+                       v_DSP_LINE_FLAG1_NUM(vsync_len + upper_margin + y_res);
                lcdc_msk_reg(lcdc_dev, LINE_FLAG, mask, val);
        }
        rk3368_lcdc_post_cfg(dev_drv);
@@ -1590,6 +1628,8 @@ static void rk3368_lcdc_bcsh_path_sel(struct rk_lcdc_driver *dev_drv)
            container_of(dev_drv, struct lcdc_device, driver);
        u32 bcsh_ctrl;
 
+       lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_OVERLAY_MODE,
+                    v_OVERLAY_MODE(dev_drv->overlay_mode));
        if (dev_drv->overlay_mode == VOP_YUV_DOMAIN) {
                if (dev_drv->output_color == COLOR_YCBCR)       /* bypass */
                        lcdc_msk_reg(lcdc_dev, BCSH_CTRL,
@@ -1606,7 +1646,8 @@ static void rk3368_lcdc_bcsh_path_sel(struct rk_lcdc_driver *dev_drv)
                /* bypass  --need check,if bcsh close? */
                if (dev_drv->output_color == COLOR_RGB) {
                        bcsh_ctrl = lcdc_readl(lcdc_dev, BCSH_CTRL);
-                       if ((bcsh_ctrl & m_BCSH_EN) == 1)/*bcsh enabled */
+                       if (((bcsh_ctrl & 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,
@@ -1627,6 +1668,53 @@ static void rk3368_lcdc_bcsh_path_sel(struct rk_lcdc_driver *dev_drv)
        }
 }
 
+static int rk3368_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact,
+                                 u16 *yact, int *format, u32 *dsp_addr)
+{
+       struct lcdc_device *lcdc_dev = container_of(dev_drv,
+                                                   struct lcdc_device, driver);
+       u32 val;
+
+       spin_lock(&lcdc_dev->reg_lock);
+
+       val = lcdc_readl(lcdc_dev, WIN0_ACT_INFO);
+       *xact = (val & m_WIN0_ACT_WIDTH) + 1;
+       *yact = ((val & m_WIN0_ACT_HEIGHT)>>16) + 1;
+
+       val = lcdc_readl(lcdc_dev, WIN0_CTRL0);
+       *format = (val & m_WIN0_DATA_FMT) >> 1;
+       *dsp_addr = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
+
+       spin_unlock(&lcdc_dev->reg_lock);
+
+       return 0;
+}
+
+static int rk3368_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst,
+                             int format, u16 xact, u16 yact, u16 xvir)
+{
+       struct lcdc_device *lcdc_dev = container_of(dev_drv,
+                                                   struct lcdc_device, driver);
+       u32 val, mask;
+       int swap = (format == RGB888) ? 1 : 0;
+
+       mask = m_WIN0_DATA_FMT | m_WIN0_RB_SWAP;
+       val = v_WIN0_DATA_FMT(format) | v_WIN0_RB_SWAP(swap);
+       lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask, val);
+
+       lcdc_msk_reg(lcdc_dev, WIN0_VIR, m_WIN0_VIR_STRIDE,
+                       v_WIN0_VIR_STRIDE(xvir));
+       lcdc_writel(lcdc_dev, WIN0_ACT_INFO, v_WIN0_ACT_WIDTH(xact) |
+                   v_WIN0_ACT_HEIGHT(yact));
+
+       lcdc_writel(lcdc_dev, WIN0_YRGB_MST, rgb_mst);
+
+       lcdc_cfg_done(lcdc_dev);
+
+       return 0;
+}
+
+
 static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
 {
        u16 face = 0;
@@ -1724,9 +1812,13 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        v = 0 << 15 | (1 << (15 + 16));
                        break;
                case SCREEN_HDMI:
-                       face = OUT_RGB_AAA;
-                       mask = m_HDMI_OUT_EN;
-                       val = v_HDMI_OUT_EN(1);
+                       /*face = OUT_RGB_AAA;*/
+                        if (screen->color_mode == COLOR_RGB)
+                                dev_drv->overlay_mode = VOP_RGB_DOMAIN;
+                        else
+                                dev_drv->overlay_mode = VOP_YUV_DOMAIN;
+                       mask = m_HDMI_OUT_EN  | m_RGB_OUT_EN;
+                       val = v_HDMI_OUT_EN(1) | v_RGB_OUT_EN(0);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
                        mask = m_HDMI_HSYNC_POL | m_HDMI_VSYNC_POL |
                            m_HDMI_DEN_POL | m_HDMI_DCLK_POL;
@@ -1736,8 +1828,8 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                            v_HDMI_DCLK_POL(screen->pin_dclk);
                        break;
                case SCREEN_MIPI:
-                       mask = m_MIPI_OUT_EN;
-                       val = v_MIPI_OUT_EN(1);
+                       mask = m_MIPI_OUT_EN  | m_RGB_OUT_EN;
+                       val = v_MIPI_OUT_EN(1) | v_RGB_OUT_EN(0);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
                        mask = m_MIPI_HSYNC_POL | m_MIPI_VSYNC_POL |
                            m_MIPI_DEN_POL | m_MIPI_DCLK_POL;
@@ -1747,8 +1839,10 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                            v_MIPI_DCLK_POL(screen->pin_dclk);
                        break;
                case SCREEN_DUAL_MIPI:
-                       mask = m_MIPI_OUT_EN | m_DOUB_CHANNEL_EN;
-                       val = v_MIPI_OUT_EN(1) | v_DOUB_CHANNEL_EN(1);
+                       mask = m_MIPI_OUT_EN | m_DOUB_CHANNEL_EN  |
+                               m_RGB_OUT_EN;
+                       val = v_MIPI_OUT_EN(1) | v_DOUB_CHANNEL_EN(1) |
+                               v_RGB_OUT_EN(0);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
                        mask = m_MIPI_HSYNC_POL | m_MIPI_VSYNC_POL |
                            m_MIPI_DEN_POL | m_MIPI_DCLK_POL;
@@ -1758,10 +1852,10 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                            v_MIPI_DCLK_POL(screen->pin_dclk);
                        break;
                case SCREEN_EDP:
-                       face = OUT_RGB_AAA;     /*RGB AAA output */
+                       face = OUT_P888;        /*RGB 888 output */
 
-                       mask = m_EDP_OUT_EN;
-                       val = v_EDP_OUT_EN(1);
+                       mask = m_EDP_OUT_EN | m_RGB_OUT_EN;
+                       val = v_EDP_OUT_EN(1) | v_RGB_OUT_EN(0);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
                        /*because edp have to sent aaa fmt */
                        mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
@@ -1798,13 +1892,32 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val);
                /*BG color */
                mask = m_DSP_BG_BLUE | m_DSP_BG_GREEN | m_DSP_BG_RED;
-               val = v_DSP_BG_BLUE(0) | v_DSP_BG_GREEN(0) | v_DSP_BG_RED(0);
+               if (dev_drv->overlay_mode == VOP_YUV_DOMAIN)
+                       val = v_DSP_BG_BLUE(0x80) | v_DSP_BG_GREEN(0x10) |
+                               v_DSP_BG_RED(0x80);
+               else
+                       val = v_DSP_BG_BLUE(0) | v_DSP_BG_GREEN(0) |
+                               v_DSP_BG_RED(0);
                lcdc_msk_reg(lcdc_dev, DSP_BG, mask, val);
+               dev_drv->output_color = screen->color_mode;
+               if (screen->dsp_lut == NULL)
+                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                                    v_DSP_LUT_EN(0));
+               else
+                       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                                    v_DSP_LUT_EN(1));
+               if (screen->cabc_lut == NULL) {
+                       lcdc_msk_reg(lcdc_dev, CABC_CTRL0, m_CABC_EN,
+                                    v_CABC_EN(0));
+               } else {
+                       lcdc_msk_reg(lcdc_dev, CABC_CTRL1, m_CABC_LUT_EN,
+                                    v_CABC_LUT_EN(1));
+               }
                rk3368_lcdc_bcsh_path_sel(dev_drv);
                rk3368_config_timing(dev_drv);
        }
        spin_unlock(&lcdc_dev->reg_lock);
-       rk3368_lcdc_set_dclk(dev_drv);
+       rk3368_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();
@@ -1864,9 +1977,10 @@ static int rk3368_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv)
            v_LINE_FLAG0_INTR_CLR(1) | v_LINE_FLAG1_INTR_CLR(1);
        lcdc_msk_reg(lcdc_dev, INTR_CLEAR, mask, val);
 
-       mask = m_FS_INTR_EN | m_LINE_FLAG0_INTR_EN | m_BUS_ERROR_INTR_EN;
+       mask = m_FS_INTR_EN | m_LINE_FLAG0_INTR_EN |
+               m_BUS_ERROR_INTR_EN | m_LINE_FLAG1_INTR_EN;
        val = v_FS_INTR_EN(1) | v_LINE_FLAG0_INTR_EN(1) |
-           v_BUS_ERROR_INTR_EN(1);
+           v_BUS_ERROR_INTR_EN(1) | v_LINE_FLAG1_INTR_EN(0);
        lcdc_msk_reg(lcdc_dev, INTR_EN, mask, val);
 
 #ifdef LCDC_IRQ_EMPTY_DEBUG
@@ -1888,15 +2002,13 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
-#ifndef CONFIG_RK_FPGA
+#if 0/*ndef CONFIG_RK_FPGA*/
        int sys_status =
            (dev_drv->id == 0) ? SYS_STATUS_LCDC0 : SYS_STATUS_LCDC1;
 #endif
        /*enable clk,when first layer open */
        if ((open) && (!lcdc_dev->atv_layer_cnt)) {
-#ifndef CONFIG_RK_FPGA
-               rockchip_set_system_status(sys_status);
-#endif
+               /*rockchip_set_system_status(sys_status);*/
                rk3368_lcdc_pre_init(dev_drv);
                rk3368_lcdc_clk_enable(lcdc_dev);
 #if defined(CONFIG_ROCKCHIP_IOMMU)
@@ -1922,7 +2034,7 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                /*if (dev_drv->iommu_enabled)
                   rk3368_lcdc_mmu_en(dev_drv); */
                if ((support_uboot_display() && (lcdc_dev->prop == PRMRY))) {
-                       /*rk3368_lcdc_set_dclk(dev_drv); */
+                       rk3368_lcdc_set_dclk(dev_drv, 0);
                        rk3368_lcdc_enable_irq(dev_drv);
                } else {
                        rk3368_load_screen(dev_drv, 1);
@@ -1931,7 +2043,11 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                        rk3368_lcdc_set_bcsh(dev_drv, 1);
                spin_lock(&lcdc_dev->reg_lock);
                if (dev_drv->cur_screen->dsp_lut)
-                       rk3368_lcdc_set_lut(dev_drv);
+                       rk3368_lcdc_set_lut(dev_drv,
+                                           dev_drv->cur_screen->dsp_lut);
+               if (dev_drv->cur_screen->cabc_lut)
+                       rk3368_set_cabc_lut(dev_drv,
+                                           dev_drv->cur_screen->cabc_lut);
                spin_unlock(&lcdc_dev->reg_lock);
        }
 
@@ -1981,7 +2097,9 @@ static int win_0_1_display(struct lcdc_device *lcdc_dev,
                win->area[0].uv_addr = uv_addr;
                lcdc_writel(lcdc_dev, WIN0_YRGB_MST + off, win->area[0].y_addr);
                lcdc_writel(lcdc_dev, WIN0_CBR_MST + off, win->area[0].uv_addr);
-               /*lcdc_cfg_done(lcdc_dev); */
+                if (win->area[0].fbdc_en == 1)
+                        lcdc_writel(lcdc_dev, IFBDC_BASE_ADDR,
+                                        win->area[0].y_addr);
        }
        spin_unlock(&lcdc_dev->reg_lock);
 
@@ -2010,6 +2128,9 @@ static int win_2_3_display(struct lcdc_device *lcdc_dev,
                lcdc_writel(lcdc_dev, WIN2_MST1 + off, win->area[1].y_addr);
                lcdc_writel(lcdc_dev, WIN2_MST2 + off, win->area[2].y_addr);
                lcdc_writel(lcdc_dev, WIN2_MST3 + off, win->area[3].y_addr);
+                if (win->area[0].fbdc_en == 1)
+                        lcdc_writel(lcdc_dev, IFBDC_BASE_ADDR,
+                                        win->area[0].y_addr);
        }
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
@@ -2152,6 +2273,7 @@ static int rk3368_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
                break;
        case YUV420:
        case YUV420_A:
+       case YUV420_NV21:
                cbcr_srcW = srcW / 2;
                cbcr_dstW = dstW;
                cbcr_srcH = srcH / 2;
@@ -2208,6 +2330,7 @@ static int rk3368_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
        /*line buffer mode */
        if ((win->area[0].format == YUV422) ||
            (win->area[0].format == YUV420) ||
+           (win->area[0].format == YUV420_NV21) ||
            (win->area[0].format == YUV422_A) ||
            (win->area[0].format == YUV420_A)) {
                if (win->cbr_hor_scl_mode == SCALE_DOWN) {
@@ -2516,30 +2639,87 @@ static int rk3368_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
        return 0;
 }
 
+static int dsp_x_pos(int mirror_en, struct rk_screen *screen,
+                    struct rk_lcdc_win_area *area)
+{
+       int pos;
+
+       if (screen->x_mirror && mirror_en)
+               pr_err("not support both win and global mirror\n");
+
+       if ((!mirror_en) && (!screen->x_mirror))
+               pos = area->xpos + screen->mode.left_margin +
+                       screen->mode.hsync_len;
+       else
+               pos = screen->mode.xres - area->xpos -
+                       area->xsize + screen->mode.left_margin +
+                       screen->mode.hsync_len;
+
+       return pos;
+}
+
+static int dsp_y_pos(int mirror_en, struct rk_screen *screen,
+                    struct rk_lcdc_win_area *area)
+{
+       int pos;
+
+       if (screen->y_mirror && mirror_en)
+               pr_err("not support both win and global mirror\n");
+       if (screen->mode.vmode == FB_VMODE_NONINTERLACED) {
+               if ((!mirror_en) && (!screen->y_mirror))
+                       pos = area->ypos + screen->mode.upper_margin +
+                               screen->mode.vsync_len;
+               else
+                       pos = screen->mode.yres - area->ypos -
+                               area->ysize + screen->mode.upper_margin +
+                               screen->mode.vsync_len;
+       } else if (screen->mode.vmode == FB_VMODE_INTERLACED) {
+               pos = area->ypos / 2 + screen->mode.upper_margin +
+                       screen->mode.vsync_len;
+               area->ysize /= 2;
+       }
+
+       return pos;
+}
+
 static int win_0_1_set_par(struct lcdc_device *lcdc_dev,
                           struct rk_screen *screen, struct rk_lcdc_win *win)
 {
        u32 xact, yact, xvir, yvir, xpos, ypos;
-       u8 fmt_cfg = 0, swap_rb;
+       u8 fmt_cfg = 0, swap_rb, swap_uv = 0;
        char fmt[9] = "NULL";
 
-       if (!win->mirror_en) {
-               xpos = win->area[0].xpos + screen->mode.left_margin +
-                   screen->mode.hsync_len;
-               ypos = win->area[0].ypos + screen->mode.upper_margin +
-                   screen->mode.vsync_len;
-       } else {
-               xpos = screen->mode.xres - win->area[0].xpos -
-                       win->area[0].xsize +
-                       screen->mode.left_margin + screen->mode.hsync_len;
-               ypos = screen->mode.yres - win->area[0].ypos -
-                       win->area[0].ysize + screen->mode.upper_margin +
-                       screen->mode.vsync_len;
-       }
+       xpos = dsp_x_pos(win->mirror_en, screen, &win->area[0]);
+       ypos = dsp_y_pos(win->mirror_en, screen, &win->area[0]);
+
        spin_lock(&lcdc_dev->reg_lock);
        if (likely(lcdc_dev->clk_on)) {
                rk3368_lcdc_cal_scl_fac(win);   /*fac,lb,gt2,gt4 */
                switch (win->area[0].format) {
+               case FBDC_RGB_565:
+                       fmt_cfg = 2;
+                       swap_rb = 0;
+                       win->fmt_10 = 0;
+                       win->area[0].fbdc_fmt_cfg = 0x05;
+                       break;
+               case FBDC_ARGB_888:
+                       fmt_cfg = 0;
+                       swap_rb = 0;
+                       win->fmt_10 = 0;
+                       win->area[0].fbdc_fmt_cfg = 0x0c;
+                       break;
+               case FBDC_ABGR_888:
+                       fmt_cfg = 0;
+                       swap_rb = 1;
+                       win->fmt_10 = 0;
+                       win->area[0].fbdc_fmt_cfg = 0x0c;
+                       break;
+               case FBDC_RGBX_888:
+                       fmt_cfg = 0;
+                       swap_rb = 0;
+                       win->fmt_10 = 0;
+                       win->area[0].fbdc_fmt_cfg = 0x3a;
+                       break;
                case ARGB888:
                        fmt_cfg = 0;
                        swap_rb = 0;
@@ -2571,6 +2751,12 @@ static int win_0_1_set_par(struct lcdc_device *lcdc_dev,
                        swap_rb = 0;
                        win->fmt_10 = 0;
                        break;
+               case YUV420_NV21:
+                       fmt_cfg = 4;
+                       swap_rb = 0;
+                       swap_uv = 1;
+                       win->fmt_10 = 0;
+                       break;
                case YUV444:
                        fmt_cfg = 6;
                        swap_rb = 0;
@@ -2598,6 +2784,7 @@ static int win_0_1_set_par(struct lcdc_device *lcdc_dev,
                }
                win->area[0].fmt_cfg = fmt_cfg;
                win->area[0].swap_rb = swap_rb;
+               win->area[0].swap_uv = swap_uv;
                win->area[0].dsp_stx = xpos;
                win->area[0].dsp_sty = ypos;
                xact = win->area[0].xact;
@@ -2627,11 +2814,31 @@ static int win_2_3_set_par(struct lcdc_device *lcdc_dev,
        u8 fmt_cfg, swap_rb;
        char fmt[9] = "NULL";
 
+       if (win->mirror_en)
+               pr_err("win[%d] not support y mirror\n", win->id);
        spin_lock(&lcdc_dev->reg_lock);
        if (likely(lcdc_dev->clk_on)) {
                DBG(2, "lcdc[%d]:win[%d]>>\n>\n", lcdc_dev->id, win->id);
                for (i = 0; i < win->area_num; i++) {
                        switch (win->area[i].format) {
+                       case FBDC_RGB_565:
+                               fmt_cfg = 2;
+                               swap_rb = 0;
+                               win->fmt_10 = 0;
+                               win->area[0].fbdc_fmt_cfg = 0x05;
+                               break;
+                       case FBDC_ARGB_888:
+                               fmt_cfg = 0;
+                               swap_rb = 0;
+                               win->fmt_10 = 0;
+                               win->area[0].fbdc_fmt_cfg = 0x0c;
+                               break;
+                       case FBDC_RGBX_888:
+                               fmt_cfg = 0;
+                               swap_rb = 0;
+                               win->fmt_10 = 0;
+                               win->area[0].fbdc_fmt_cfg = 0x3a;
+                               break;
                        case ARGB888:
                                fmt_cfg = 0;
                                swap_rb = 0;
@@ -2656,20 +2863,22 @@ static int win_2_3_set_par(struct lcdc_device *lcdc_dev,
                        }
                        win->area[i].fmt_cfg = fmt_cfg;
                        win->area[i].swap_rb = swap_rb;
-                       win->area[i].dsp_stx = win->area[i].xpos +
-                           screen->mode.left_margin + screen->mode.hsync_len;
-                       if (screen->y_mirror == 1) {
-                               win->area[i].dsp_sty = screen->mode.yres -
-                                   win->area[i].ypos -
-                                   win->area[i].ysize +
-                                   screen->mode.upper_margin +
-                                   screen->mode.vsync_len;
-                       } else {
-                               win->area[i].dsp_sty = win->area[i].ypos +
-                                   screen->mode.upper_margin +
-                                   screen->mode.vsync_len;
+                       win->area[i].dsp_stx =
+                                       dsp_x_pos(win->mirror_en, screen,
+                                                 &win->area[i]);
+                       win->area[i].dsp_sty =
+                                       dsp_y_pos(win->mirror_en, screen,
+                                                 &win->area[i]);
+                       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;
                        }
-
                        DBG(2, "fmt:%s:xsize:%d>>ysize:%d>>xpos:%d>>ypos:%d\n",
                            get_format_string(win->area[i].format, fmt),
                            win->area[i].xsize, win->area[i].ysize,
@@ -2828,7 +3037,6 @@ static int rk3368_lcdc_get_backlight_device(struct rk_lcdc_driver *dev_drv)
 
 static int rk3368_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv)
 {
-       u32 reg;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        if (dev_drv->suspend_flag)
@@ -2843,8 +3051,6 @@ static int rk3368_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv)
        dev_drv->suspend_flag = 1;
        flush_kthread_worker(&dev_drv->update_regs_worker);
 
-       for (reg = MMU_DTE_ADDR; reg <= MMU_AUTO_GATING; reg += 4)
-               lcdc_readl(lcdc_dev, reg);
        if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
                dev_drv->trsm_ops->disable();
 
@@ -2879,9 +3085,6 @@ static int rk3368_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;
@@ -2893,27 +3096,12 @@ static int rk3368_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
                rk3368_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);
-                               g = (v & 0xff00);
-                               r = (v & 0xff0000);
-                               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->dsp_lut)
+                       rk3368_lcdc_set_lut(dev_drv,
+                                           dev_drv->cur_screen->dsp_lut);
+               if (dev_drv->cur_screen->cabc_lut)
+                       rk3368_set_cabc_lut(dev_drv,
+                                           dev_drv->cur_screen->cabc_lut);
 
                lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DSP_OUT_ZERO,
                             v_DSP_OUT_ZERO(0));
@@ -2932,7 +3120,6 @@ static int rk3368_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
 
        if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
                dev_drv->trsm_ops->enable();
-
        return 0;
 }
 
@@ -2958,7 +3145,23 @@ static int rk3368_lcdc_blank(struct rk_lcdc_driver *dev_drv,
 
 static int rk3368_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv, int win_id)
 {
-       return 0;
+       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);
+
+       return win_status;
 }
 
 /*overlay will be do at regupdate*/
@@ -3187,10 +3390,10 @@ static ssize_t rk3368_lcdc_get_disp_info(struct rk_lcdc_driver *dev_drv,
                /*WIN2 */
                win_ctrl = lcdc_readl(lcdc_dev, WIN2_CTRL0);
                w2_state = win_ctrl & m_WIN2_EN;
-               w2_0_state = (win_ctrl & m_WIN2_MST0_EN) >> 4;
-               w2_1_state = (win_ctrl & m_WIN2_MST1_EN) >> 5;
-               w2_2_state = (win_ctrl & m_WIN2_MST2_EN) >> 6;
-               w2_3_state = (win_ctrl & m_WIN2_MST3_EN) >> 7;
+               w2_0_state = (win_ctrl & 0x10) >> 4;
+               w2_1_state = (win_ctrl & 0x100) >> 8;
+               w2_2_state = (win_ctrl & 0x1000) >> 12;
+               w2_3_state = (win_ctrl & 0x10000) >> 16;
                vir_info = lcdc_readl(lcdc_dev, WIN2_VIR0_1);
                w2_0_vir_y = vir_info & m_WIN2_VIR_STRIDE0;
                w2_1_vir_y = (vir_info & m_WIN2_VIR_STRIDE1) >> 16;
@@ -3244,9 +3447,9 @@ static ssize_t rk3368_lcdc_get_disp_info(struct rk_lcdc_driver *dev_drv,
                win_ctrl = lcdc_readl(lcdc_dev, WIN3_CTRL0);
                w3_state = win_ctrl & m_WIN3_EN;
                w3_0_state = (win_ctrl & m_WIN3_MST0_EN) >> 4;
-               w3_1_state = (win_ctrl & m_WIN3_MST1_EN) >> 5;
-               w3_2_state = (win_ctrl & m_WIN3_MST2_EN) >> 6;
-               w3_3_state = (win_ctrl & m_WIN3_MST3_EN) >> 7;
+               w3_1_state = (win_ctrl & m_WIN3_MST1_EN) >> 8;
+               w3_2_state = (win_ctrl & m_WIN3_MST2_EN) >> 12;
+               w3_3_state = (win_ctrl & m_WIN3_MST3_EN) >> 16;
                vir_info = lcdc_readl(lcdc_dev, WIN3_VIR0_1);
                w3_0_vir_y = vir_info & m_WIN3_VIR_STRIDE0;
                w3_1_vir_y = (vir_info & m_WIN3_VIR_STRIDE1) >> 16;
@@ -3504,13 +3707,7 @@ static int rk3368_lcdc_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps,
                    screen->mode.xres + screen->mode.hsync_len;
                dev_drv->pixclock = div_u64(ft, x_total * y_total);
                dotclk = div_u64(1000000000000llu, dev_drv->pixclock);
-               ret = clk_set_rate(lcdc_dev->pll_sclk, dotclk); /*set pll */
-               if (ret)
-                       dev_err(dev_drv->dev,
-                               "set lcdc%d pll_sclk failed\n", lcdc_dev->id);
-
                ret = clk_set_rate(lcdc_dev->dclk, dotclk);
-               /*SET NEW PLL FOR RK3368 */
        }
 
        pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk));
@@ -3562,46 +3759,6 @@ static int rk3368_lcdc_get_win_id(struct rk_lcdc_driver *dev_drv,
        return win_id;
 }
 
-static int rk3368_set_dsp_lut(struct rk_lcdc_driver *dev_drv, int *lut)
-{
-       int i, j;
-       int __iomem *c;
-       int v, r, g, b;
-       int ret = 0;
-
-       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));
-       lcdc_cfg_done(lcdc_dev);
-       mdelay(25);
-       if (dev_drv->cur_screen->dsp_lut) {
-               for (i = 0; i < 256; i++) {
-                       dev_drv->cur_screen->dsp_lut[i] = lut[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++;
-                       }
-               }
-       } else {
-               dev_err(dev_drv->dev, "no buffer to backup lut data!\n");
-               ret = -1;
-       }
-
-       do {
-               lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
-                            v_DSP_LUT_EN(1));
-               lcdc_cfg_done(lcdc_dev);
-       } while (!lcdc_read_bit(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN));
-       return ret;
-}
-
 static int rk3368_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
 {
        struct lcdc_device *lcdc_dev =
@@ -3757,11 +3914,11 @@ static int rk3368_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
 }
 
 static struct lcdc_cabc_mode cabc_mode[4] = {
-       /* pixel_num,8 stage_up, stage_down */
-       {5, 148, 20, 300},      /*mode 1 */
-       {10, 148, 20, 300},     /*mode 2 */
-       {15, 148, 20, 300},     /*mode 3 */
-       {20, 148, 20, 300},     /*mode 4 */
+      /* calc,     up,     down,   global_limit   */
+       {5,    256,  256,   256},  /*mode 1   0*/
+       {5,    258,  253,   277},  /*mode 2   15%*/
+       {5,    259,  252,   330},  /*mode 3   40%*/
+       {5,    267,  244,   400},  /*mode 4   60%*/
 };
 
 static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
@@ -3771,40 +3928,20 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
        struct rk_screen *screen = dev_drv->cur_screen;
        u32 total_pixel, calc_pixel, stage_up, stage_down;
        u32 pixel_num, global_su;
-       u32 stage_up_rec, stage_down_rec, global_su_rec;
+       u32 stage_up_rec, stage_down_rec, global_su_rec, gamma_global_su_rec;
        u32 mask = 0, val = 0, cabc_en = 0;
-       u32 __maybe_unused max_mode_num =
-           sizeof(cabc_mode) / sizeof(struct lcdc_cabc_mode);
+       int *cabc_lut = NULL;
 
-       dev_drv->cabc_mode = mode;
-#if 0/*ndef CONFIG_RK_FPGA*/
-       /* iomux connect to vop or pwm */
-       if (mode == 0) {
-               DBG(3, "close cabc and select rk pwm\n");
-               val = 0x30002;
-               writel_relaxed(val, RK_GRF_VIRT + rk3368_GRF_GPIO3C_IOMUX);
-               cabc_en = 0;
-       } else if (mode > 0 && mode <= max_mode_num) {
-               DBG(3, "open cabc and select vop pwm\n");
-               val = 0x30003;
-               writel_relaxed(val, RK_GRF_VIRT + rk3368_GRF_GPIO3C_IOMUX);
-               cabc_en = 1;
-       } else if (mode > 0x10 && mode <= (max_mode_num + 0x10)) {
-               DBG(3, "open cabc and select rk pwm\n");
-               val = 0x30003;
-               writel_relaxed(val, RK_GRF_VIRT + rk3368_GRF_GPIO3C_IOMUX);
-               cabc_en = 1;
-               mode -= 0x10;
-       } else if (mode == 0xff) {
-               DBG(3, "close cabc and select vop pwm\n");
-               val = 0x30002;
-               writel_relaxed(val, RK_GRF_VIRT + rk3368_GRF_GPIO3C_IOMUX);
-               cabc_en = 0;
-       } else {
-               dev_err(lcdc_dev->dev, "invalid cabc mode value:%d", mode);
+       if (!screen->cabc_lut) {
+               pr_err("screen cabc lut not config, so not open cabc\n");
                return 0;
+       } else {
+               cabc_lut = screen->cabc_lut;
        }
-#endif
+
+       dev_drv->cabc_mode = mode;
+       cabc_en = (mode > 0) ? 1 : 0;
+
        if (cabc_en == 0) {
                spin_lock(&lcdc_dev->reg_lock);
                if (lcdc_dev->clk_on) {
@@ -3825,16 +3962,18 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
 
        stage_up_rec = 256 * 256 / stage_up;
        stage_down_rec = 256 * 256 / stage_down;
-       global_su_rec = 256 * 256 / global_su;
+       global_su_rec = (256 * 256 / global_su) - 1;
+       gamma_global_su_rec = cabc_lut[global_su_rec];
 
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
-               mask = m_CABC_CALC_PIXEL_NUM;
-               val = v_CABC_CALC_PIXEL_NUM(calc_pixel);
+               mask = m_CABC_CALC_PIXEL_NUM | m_CABC_EN;
+               val = v_CABC_CALC_PIXEL_NUM(calc_pixel) |
+                       v_CABC_EN(cabc_en);
                lcdc_msk_reg(lcdc_dev, CABC_CTRL0, mask, val);
 
-               mask = m_CABC_TOTAL_PIXEL_NUM;
-               val = v_CABC_TOTAL_PIXEL_NUM(total_pixel);
+               mask = m_CABC_TOTAL_PIXEL_NUM | m_CABC_LUT_EN;
+               val = v_CABC_TOTAL_PIXEL_NUM(total_pixel) | v_CABC_LUT_EN(1);
                lcdc_msk_reg(lcdc_dev, CABC_CTRL1, mask, val);
 
                mask = m_CABC_STAGE_UP | m_CABC_STAGE_UP_REC |
@@ -3842,7 +3981,7 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                val = v_CABC_STAGE_UP(stage_up) |
                    v_CABC_STAGE_UP_REC(stage_up_rec) |
                    v_CABC_GLOBAL_SU_LIMIT_EN(1) |
-                   v_CABC_GLOBAL_SU_REC(global_su_rec);
+                   v_CABC_GLOBAL_SU_REC(gamma_global_su_rec);
                lcdc_msk_reg(lcdc_dev, CABC_CTRL2, mask, val);
 
                mask = m_CABC_STAGE_DOWN | m_CABC_STAGE_DOWN_REC |
@@ -3993,16 +4132,18 @@ static int rk3368_lcdc_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open)
 
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
-               rk3368_lcdc_bcsh_path_sel(dev_drv);
                if (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;
                }
+               rk3368_lcdc_bcsh_path_sel(dev_drv);
                lcdc_cfg_done(lcdc_dev);
        }
        spin_unlock(&lcdc_dev->reg_lock);
@@ -4044,15 +4185,7 @@ static int rk3368_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
 
-       rk3368_lcdc_get_backlight_device(dev_drv);
-
        if (enable) {
-               /* close the backlight */
-               if (lcdc_dev->backlight) {
-                       lcdc_dev->backlight->props.power = FB_BLANK_POWERDOWN;
-                       backlight_update_status(lcdc_dev->backlight);
-               }
-#if 1
                spin_lock(&lcdc_dev->reg_lock);
                if (likely(lcdc_dev->clk_on)) {
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DSP_BLACK_EN,
@@ -4060,11 +4193,7 @@ static int rk3368_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
                        lcdc_cfg_done(lcdc_dev);
                }
                spin_unlock(&lcdc_dev->reg_lock);
-#endif
-               if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
-                       dev_drv->trsm_ops->disable();
        } else {
-#if 1
                spin_lock(&lcdc_dev->reg_lock);
                if (likely(lcdc_dev->clk_on)) {
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DSP_BLACK_EN,
@@ -4073,7 +4202,29 @@ static int rk3368_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
                        lcdc_cfg_done(lcdc_dev);
                }
                spin_unlock(&lcdc_dev->reg_lock);
-#endif
+       }
+
+       return 0;
+}
+
+
+static int rk3368_lcdc_backlight_close(struct rk_lcdc_driver *dev_drv,
+                                      int enable)
+{
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+
+       rk3368_lcdc_get_backlight_device(dev_drv);
+
+       if (enable) {
+               /* close the backlight */
+               if (lcdc_dev->backlight) {
+                       lcdc_dev->backlight->props.power = FB_BLANK_POWERDOWN;
+                       backlight_update_status(lcdc_dev->backlight);
+               }
+               if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+                       dev_drv->trsm_ops->disable();
+       } else {
                if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
                        dev_drv->trsm_ops->enable();
                msleep(100);
@@ -4087,10 +4238,20 @@ static int rk3368_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
        return 0;
 }
 
+static int rk3368_lcdc_set_overscan(struct rk_lcdc_driver *dev_drv,
+                                   struct overscan *overscan)
+{
+        rk3368_lcdc_post_cfg(dev_drv);
+
+        return 0;
+}
+
 static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .open = rk3368_lcdc_open,
        .win_direct_en = rk3368_lcdc_win_direct_en,
        .load_screen = rk3368_load_screen,
+       .get_dspbuf_info = rk3368_get_dspbuf_info,
+       .post_dspbuf = rk3368_post_dspbuf,
        .set_par = rk3368_lcdc_set_par,
        .pan_display = rk3368_lcdc_pan_display,
        .direct_set_addr = rk3368_lcdc_direct_set_win_addr,
@@ -4105,7 +4266,8 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .fps_mgr = rk3368_lcdc_fps_mgr,
        .fb_get_win_id = rk3368_lcdc_get_win_id,
        .fb_win_remap = rk3368_fb_win_remap,
-       .set_dsp_lut = rk3368_set_dsp_lut,
+       .set_dsp_lut = rk3368_lcdc_set_lut,
+       .set_cabc_lut = rk3368_set_cabc_lut,
        .poll_vblank = rk3368_lcdc_poll_vblank,
        .dpi_open = rk3368_lcdc_dpi_open,
        .dpi_win_sel = rk3368_lcdc_dpi_win_sel,
@@ -4121,7 +4283,9 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .cfg_done = rk3368_lcdc_config_done,
        .set_irq_to_cpu = rk3368_lcdc_set_irq_to_cpu,
        .dsp_black = rk3368_lcdc_dsp_black,
+       .backlight_close = rk3368_lcdc_backlight_close,
        .mmu_en    = rk3368_lcdc_mmu_en,
+       .set_overscan   = rk3368_lcdc_set_overscan,
 };
 
 #ifdef LCDC_IRQ_EMPTY_DEBUG
@@ -4336,6 +4500,19 @@ static int rk3368_lcdc_probe(struct platform_device *pdev)
        if (IS_ERR(lcdc_dev->regsbak))
                return PTR_ERR(lcdc_dev->regsbak);
        lcdc_dev->dsp_lut_addr_base = (lcdc_dev->regs + GAMMA_LUT_ADDR);
+       lcdc_dev->cabc_lut_addr_base = (lcdc_dev->regs + CABC_GAMMA_LUT_ADDR);
+       lcdc_dev->grf_base =
+               syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+       if (IS_ERR(lcdc_dev->grf_base)) {
+               dev_err(&pdev->dev, "can't find lcdc grf property\n");
+               return PTR_ERR(lcdc_dev->grf_base);
+       }
+       lcdc_dev->pmugrf_base =
+               syscon_regmap_lookup_by_phandle(np, "rockchip,pmugrf");
+       if (IS_ERR(lcdc_dev->pmugrf_base)) {
+               dev_err(&pdev->dev, "can't find lcdc pmu grf property\n");
+               return PTR_ERR(lcdc_dev->pmugrf_base);
+       }
        lcdc_dev->id = 0;
        dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id);
        dev_drv = &lcdc_dev->driver;
@@ -4393,8 +4570,8 @@ static void rk3368_lcdc_shutdown(struct platform_device *pdev)
 {
        struct lcdc_device *lcdc_dev = platform_get_drvdata(pdev);
 
+       rk3368_lcdc_early_suspend(&lcdc_dev->driver);
        rk3368_lcdc_deint(lcdc_dev);
-       rk_disp_pwr_disable(&lcdc_dev->driver);
 }
 
 #if defined(CONFIG_OF)