rk3368 lcdc: enable dither up default
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / lcdc / rk3368_lcdc.c
old mode 100644 (file)
new mode 100755 (executable)
index 3611d49..7a509cd
@@ -95,6 +95,30 @@ u32 rk3368_get_hard_ware_vskiplines(u32 srch, u32 dsth)
        return vscalednmult;
 }
 
+
+static int rk3368_set_cabc_lut(struct rk_lcdc_driver *dev_drv, int *cabc_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, 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 = cabc_lut[i];
+               c = lcdc_dev->cabc_lut_addr_base + i;
+               writel_relaxed(v, c);
+       }
+       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;
@@ -102,7 +126,9 @@ static int rk3368_lcdc_set_lut(struct rk_lcdc_driver *dev_drv, int *dsp_lut)
        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, DSP_CTRL1, m_DSP_LUT_EN,
+                    v_DSP_LUT_EN(0));
        lcdc_cfg_done(lcdc_dev);
        mdelay(25);
        for (i = 0; i < 256; i++) {
@@ -110,7 +136,8 @@ static int rk3368_lcdc_set_lut(struct rk_lcdc_driver *dev_drv, int *dsp_lut)
                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));
+       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
+                    v_DSP_LUT_EN(1));
 
        return 0;
 }
@@ -125,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);
@@ -148,7 +175,7 @@ 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;
@@ -389,9 +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->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);
@@ -411,13 +438,21 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
                lcdc_grf_writel(lcdc_dev->pmugrf_base,
                                PMUGRF_SOC_CON0_VOP, v);
        }
+#if 0
        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);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_1, 0x00040b15);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_0, 0x15110903);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_1, 0x00030911);
-
+#else
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_0, 0x40000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_1, 0x0);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_0, 0x80000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_1, 0x0);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_0, 0x40000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_1, 0x0);
+#endif
        lcdc_writel(lcdc_dev, FRC_LOWER01_0, 0x12844821);
        lcdc_writel(lcdc_dev, FRC_LOWER01_1, 0x21488412);
        lcdc_writel(lcdc_dev, FRC_LOWER10_0, 0xa55a9696);
@@ -427,6 +462,10 @@ 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);
+       mask = m_DITHER_UP_EN;
+       val = v_DITHER_UP_EN(1);
+       lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
        lcdc_cfg_done(lcdc_dev);
        /*disable win0 to workaround iommu pagefault */
        /*if (dev_drv->iommu_enabled) */
@@ -438,6 +477,27 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 
 static void rk3368_lcdc_deint(struct lcdc_device *lcdc_dev)
 {
+       u32 mask, val;
+
+       rk3368_lcdc_disable_irq(lcdc_dev);
+       spin_lock(&lcdc_dev->reg_lock);
+       mask = m_WIN0_EN;
+       val = v_WIN0_EN(0);
+       lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask, val);
+       lcdc_msk_reg(lcdc_dev, WIN1_CTRL0, mask, val);
+
+       mask = m_WIN2_EN | m_WIN2_MST0_EN |
+               m_WIN2_MST1_EN |
+               m_WIN2_MST2_EN | m_WIN2_MST3_EN;
+       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_msk_reg(lcdc_dev, WIN3_CTRL0, mask, val);
+       lcdc_cfg_done(lcdc_dev);
+       spin_unlock(&lcdc_dev->reg_lock);
+       mdelay(50);
+
 }
 
 static int rk3368_lcdc_post_cfg(struct rk_lcdc_driver *dev_drv)
@@ -455,6 +515,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 +
@@ -613,6 +680,7 @@ 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;
@@ -858,10 +926,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);
@@ -999,6 +1063,57 @@ static int rk3368_init_fbdc_config(struct rk_lcdc_driver *dev_drv, int win_id)
        return 0;
 }
 
+static int rk3368_lcdc_axi_gather_cfg(struct lcdc_device *lcdc_dev,
+                                           struct rk_lcdc_win *win)
+{
+       u32 mask, val;
+       u16 yrgb_gather_num = 8;
+       u16 cbcr_gather_num = 2;
+
+       switch (win->area[0].format) {
+       case ARGB888:
+       case XBGR888:
+       case ABGR888:
+               yrgb_gather_num = 8;
+               break;
+       case RGB888:
+       case RGB565:
+               yrgb_gather_num = 4;
+               break;
+       case YUV444:
+       case YUV422:
+       case YUV420:
+       case YUV420_NV21:
+               yrgb_gather_num = 2;
+               cbcr_gather_num = 4;
+               break;
+       default:
+               dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       if ((win->id == 0) || (win->id == 1)) {
+               mask = m_WIN0_YRGB_AXI_GATHER_EN | m_WIN0_CBR_AXI_GATHER_EN |
+                       m_WIN0_YRGB_AXI_GATHER_NUM | m_WIN0_CBR_AXI_GATHER_NUM;
+               val = v_WIN0_YRGB_AXI_GATHER_EN(1) | v_WIN0_CBR_AXI_GATHER_EN(1) |
+                       v_WIN0_YRGB_AXI_GATHER_NUM(yrgb_gather_num) |
+                       v_WIN0_CBR_AXI_GATHER_NUM(cbcr_gather_num);
+               lcdc_msk_reg(lcdc_dev, WIN0_CTRL1 + (win->id * 0x40), mask, val);
+       } else if ((win->id == 2) || (win->id == 3)) {
+               mask = m_WIN0_YRGB_AXI_GATHER_EN | m_WIN0_YRGB_AXI_GATHER_NUM;
+               val = v_WIN0_YRGB_AXI_GATHER_EN(1) |
+                       v_WIN0_YRGB_AXI_GATHER_NUM(yrgb_gather_num);
+               lcdc_msk_reg(lcdc_dev, WIN2_CTRL1 + ((win->id - 2) * 0x50), mask, val);
+       } else if (win->id == 4) {
+               mask = m_HWC_AXI_GATHER_EN | m_HWC_AXI_GATHER_NUM;
+               val = v_HWC_AXI_GATHER_EN(1) |
+                       v_HWC_AXI_GATHER_NUM(yrgb_gather_num);
+               lcdc_msk_reg(lcdc_dev, HWC_CTRL1, mask, val);
+       }
+       return 0;
+}
+
 static void rk3368_lcdc_csc_mode(struct lcdc_device *lcdc_dev,
                                 struct rk_lcdc_win *win)
 {
@@ -1046,6 +1161,7 @@ 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);
+               rk3368_lcdc_axi_gather_cfg(lcdc_dev, win);
                if (win->area[0].fbdc_en) {
                        rk3368_fbdc_reg_update(&lcdc_dev->driver, win_id);
                } else {
@@ -1055,7 +1171,7 @@ static int rk3368_win_0_1_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
                }
                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) |
@@ -1063,7 +1179,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 |
@@ -1144,6 +1261,7 @@ static int rk3368_win_2_3_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
 
        if (win->state == 1) {
                rk3368_lcdc_csc_mode(lcdc_dev, win);
+               rk3368_lcdc_axi_gather_cfg(lcdc_dev, win);
                if (win->area[0].fbdc_en) {
                        rk3368_fbdc_reg_update(&lcdc_dev->driver, win_id);
                } else {
@@ -1299,6 +1417,7 @@ static int rk3368_hwc_reg_update(struct rk_lcdc_driver *dev_drv, int win_id)
 
        if (win->state == 1) {
                rk3368_lcdc_csc_mode(lcdc_dev, win);
+               rk3368_lcdc_axi_gather_cfg(lcdc_dev, win);
                mask = m_HWC_EN | m_HWC_DATA_FMT |
                    m_HWC_RB_SWAP | m_WIN0_CSC_MODE;
                val = v_HWC_EN(1) | v_HWC_DATA_FMT(win->area[0].fmt_cfg) |
@@ -1351,7 +1470,6 @@ static int rk3368_lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
        int timeout;
        unsigned long flags;
 
-       spin_lock(&lcdc_dev->reg_lock);
        if (likely(lcdc_dev->clk_on)) {
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
                             v_STANDBY_EN(lcdc_dev->standby));
@@ -1364,7 +1482,6 @@ static int rk3368_lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                /*rk3368_lcdc_post_cfg(dev_drv); */
                lcdc_cfg_done(lcdc_dev);
        }
-       spin_unlock(&lcdc_dev->reg_lock);
 
        /*if (dev_drv->wait_fs) { */
        if (0) {
@@ -1387,10 +1504,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;
 }
 
@@ -1399,20 +1513,20 @@ 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);
                }
@@ -1421,7 +1535,7 @@ static int __maybe_unused rk3368_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
        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 =
@@ -1430,8 +1544,8 @@ static int rk3368_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
 #ifdef CONFIG_RK_FPGA
        return 0;
 #endif
-
-       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 =
@@ -1465,13 +1579,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);
@@ -1543,9 +1650,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;
@@ -1589,8 +1697,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);
@@ -1643,6 +1752,108 @@ 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 lcdc_reset(struct rk_lcdc_driver *dev_drv, bool initscreen)
+{
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+       u32 mask, val;
+       u32 __maybe_unused v;
+        /*printk("0407:standby=%d,initscreen=%d,dev_drv->first_frame=%d\n",
+                lcdc_dev->standby,initscreen,dev_drv->first_frame);*/
+       if (!lcdc_dev->standby && initscreen && (dev_drv->first_frame != 1)) {
+               mdelay(150);
+               mask = m_WIN0_EN;
+               val = v_WIN0_EN(0);
+               lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask, val);
+               lcdc_msk_reg(lcdc_dev, WIN1_CTRL0, mask, val);
+
+               mask = m_WIN2_EN | m_WIN2_MST0_EN |
+                       m_WIN2_MST1_EN |
+                       m_WIN2_MST2_EN | m_WIN2_MST3_EN;
+               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_msk_reg(lcdc_dev, WIN3_CTRL0, mask, val);
+               mask = m_HDMI_OUT_EN;
+               val = v_HDMI_OUT_EN(0);
+               lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
+               lcdc_cfg_done(lcdc_dev);
+               mdelay(50);
+               writel_relaxed(0, lcdc_dev->regs + REG_CFG_DONE);
+#if 0
+               if (dev_drv->iommu_enabled) {
+                       if (dev_drv->mmu_dev)
+                               rockchip_iovmm_deactivate(dev_drv->dev);
+               }
+               lcdc_cru_writel(lcdc_dev->cru_base, 0x0318,
+                               (1 << 4)  | (1 << 5)  | (1 << 6) |
+                               (1 << 20) | (1 << 21) | (1 << 22));
+               udelay(100);
+               v = lcdc_cru_readl(lcdc_dev->cru_base, 0x0318);
+               pr_info("cru read = 0x%x\n", v);
+               lcdc_cru_writel(lcdc_dev->cru_base, 0x0318,
+                               (0 << 4)  | (0 << 5)  | (0 << 6) |
+                               (1 << 20) | (1 << 21) | (1 << 22));
+               mdelay(100);
+               if (dev_drv->iommu_enabled) {
+                       if (dev_drv->mmu_dev)
+                               rockchip_iovmm_activate(dev_drv->dev);
+               }
+               mdelay(50);
+               rk3368_lcdc_reg_restore(lcdc_dev);
+               mdelay(50);
+#endif
+       }
+       return 0;
+}
+
 static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
 {
        u16 face = 0;
@@ -1652,16 +1863,22 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
            container_of(dev_drv, struct lcdc_device, driver);
        struct rk_screen *screen = dev_drv->cur_screen;
        u32 mask, val;
+        if (!lcdc_dev->standby && initscreen && (dev_drv->first_frame != 1))
+                flush_kthread_worker(&dev_drv->update_regs_worker);
 
        spin_lock(&lcdc_dev->reg_lock);
        if (likely(lcdc_dev->clk_on)) {
                dev_drv->overlay_mode = VOP_RGB_DOMAIN;
+#if 0
                if (!lcdc_dev->standby && !initscreen) {
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
                                     v_STANDBY_EN(1));
                        lcdc_cfg_done(lcdc_dev);
                        mdelay(50);
                }
+#else
+        lcdc_reset(dev_drv, initscreen);
+#endif
                switch (screen->face) {
                case OUT_P565:
                        face = OUT_P565;
@@ -1697,16 +1914,16 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        break;
                case OUT_P888:
                        face = OUT_P888;
-                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
-                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       mask = m_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                case OUT_YUV_420:
                        /*yuv420 output prefer yuv domain overlay */
                        face = OUT_YUV_420;
                        dclk_ddr = 1;
-                       mask = m_DITHER_DOWN_EN | m_DITHER_UP_EN;
-                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       mask = m_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0);
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val);
                        break;
                default:
@@ -1741,7 +1958,10 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        break;
                case SCREEN_HDMI:
                        /*face = OUT_RGB_AAA;*/
-                       dev_drv->overlay_mode = VOP_YUV_DOMAIN;
+                        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);
@@ -1783,8 +2003,8 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        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;
-                       val = v_DITHER_DOWN_EN(0) | v_DITHER_UP_EN(0);
+                       mask = m_DITHER_DOWN_EN;
+                       val = v_DITHER_DOWN_EN(0);
 
                        mask |= m_EDP_HSYNC_POL | m_EDP_VSYNC_POL |
                            m_EDP_DEN_POL | m_EDP_DCLK_POL;
@@ -1835,8 +2055,10 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                rk3368_config_timing(dev_drv);
        }
        spin_unlock(&lcdc_dev->reg_lock);
-       rk3368_lcdc_set_dclk(dev_drv);
-       if (screen->type != SCREEN_HDMI && dev_drv->trsm_ops &&
+       rk3368_lcdc_set_dclk(dev_drv, 1);
+       if (screen->type != SCREEN_HDMI &&
+           screen->type != SCREEN_TVOUT &&
+           dev_drv->trsm_ops &&
            dev_drv->trsm_ops->enable)
                dev_drv->trsm_ops->enable();
        if (screen->init)
@@ -1895,9 +2117,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
@@ -1928,6 +2151,7 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                /*rockchip_set_system_status(sys_status);*/
                rk3368_lcdc_pre_init(dev_drv);
                rk3368_lcdc_clk_enable(lcdc_dev);
+               rk3368_lcdc_enable_irq(dev_drv);
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (!dev_drv->mmu_dev) {
@@ -1951,8 +2175,8 @@ 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_enable_irq(dev_drv);
+                       rk3368_lcdc_set_dclk(dev_drv, 0);
+                       /*rk3368_lcdc_enable_irq(dev_drv);*/
                } else {
                        rk3368_load_screen(dev_drv, 1);
                }
@@ -1962,6 +2186,9 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                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);
                spin_unlock(&lcdc_dev->reg_lock);
        }
 
@@ -1986,7 +2213,7 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
           rockchip_clear_system_status(sys_status);
           #endif
           } */
-
+        dev_drv->first_frame = 0;
        return 0;
 }
 
@@ -2011,7 +2238,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);
 
@@ -2040,6 +2269,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;
@@ -2093,11 +2325,6 @@ static int rk3368_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id)
                return -EINVAL;
        }
 
-       /*this is the first frame of the system ,enable frame start interrupt */
-       if ((dev_drv->first_frame)) {
-               dev_drv->first_frame = 0;
-               rk3368_lcdc_enable_irq(dev_drv);
-       }
 #if defined(WAIT_FOR_SYNC)
        spin_lock_irqsave(&dev_drv->cpl_lock, flags);
        init_completion(&dev_drv->frame_done);
@@ -2182,6 +2409,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;
@@ -2238,6 +2466,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) {
@@ -2593,7 +2822,7 @@ 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";
 
        xpos = dsp_x_pos(win->mirror_en, screen, &win->area[0]);
@@ -2615,6 +2844,12 @@ static int win_0_1_set_par(struct lcdc_device *lcdc_dev,
                        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;
@@ -2652,6 +2887,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;
@@ -2679,6 +2920,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;
@@ -2763,7 +3005,16 @@ static int win_2_3_set_par(struct lcdc_device *lcdc_dev,
                        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,
@@ -2903,11 +3154,13 @@ static int rk3368_lcdc_get_backlight_device(struct rk_lcdc_driver *dev_drv)
 {
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                                    struct lcdc_device, driver);
-       /*struct device_node *backlight;*/
+       struct device_node *backlight;
+       struct property *prop;
+       u32 brightness_levels[256];
+       u32 length, max, last;
 
        if (lcdc_dev->backlight)
                return 0;
-#if 0
        backlight = of_parse_phandle(lcdc_dev->dev->of_node, "backlight", 0);
        if (backlight) {
                lcdc_dev->backlight = of_find_backlight_by_node(backlight);
@@ -2916,13 +3169,24 @@ static int rk3368_lcdc_get_backlight_device(struct rk_lcdc_driver *dev_drv)
        } else {
                dev_info(lcdc_dev->dev, "No find backlight device node\n");
        }
-#endif
+       prop = of_find_property(backlight, "brightness-levels", &length);
+       if (!prop)
+               return -EINVAL;
+       max = length / sizeof(u32);
+       last = max - 1;
+       if (!of_property_read_u32_array(backlight, "brightness-levels", brightness_levels, max)) {
+               if (brightness_levels[0] > brightness_levels[last])
+                       dev_drv->cabc_pwm_pol = 1;/*negative*/
+               else
+                       dev_drv->cabc_pwm_pol = 0;/*positive*/
+       } else {
+               dev_info(lcdc_dev->dev, "Can not read brightness-levels value\n");
+       }
        return 0;
 }
 
 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)
@@ -2937,8 +3201,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_backup(lcdc_dev, reg);
        if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
                dev_drv->trsm_ops->disable();
 
@@ -2977,7 +3239,6 @@ static int rk3368_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
        if (!dev_drv->suspend_flag)
                return 0;
        rk_disp_pwr_enable(dev_drv);
-       dev_drv->suspend_flag = 0;
 
        if (1/*lcdc_dev->atv_layer_cnt*/) {
                rk3368_lcdc_clk_enable(lcdc_dev);
@@ -2987,6 +3248,9 @@ static int rk3368_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
                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));
@@ -3002,10 +3266,11 @@ static int rk3368_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
 
                spin_unlock(&lcdc_dev->reg_lock);
        }
+       dev_drv->suspend_flag = 0;
 
        if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
                dev_drv->trsm_ops->enable();
-
+       mdelay(100);
        return 0;
 }
 
@@ -3029,9 +3294,65 @@ static int rk3368_lcdc_blank(struct rk_lcdc_driver *dev_drv,
        return 0;
 }
 
-static int rk3368_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv, int win_id)
+static int rk3368_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv,
+                                           int win_id, int area_id)
 {
-       return 0;
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+        u32 win_ctrl = 0;
+        u32 area_status = 0;
+
+        switch (win_id) {
+        case 0:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN0_CTRL0);
+                area_status = win_ctrl & m_WIN0_EN;
+                break;
+        case 1:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN1_CTRL0);
+                area_status = win_ctrl & m_WIN1_EN;
+                break;
+        case 2:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN2_CTRL0);
+                if (area_id == 0)
+                        area_status = win_ctrl & m_WIN2_MST0_EN;
+                if (area_id == 1)
+                        area_status = win_ctrl & m_WIN2_MST1_EN;
+                if (area_id == 2)
+                        area_status = win_ctrl & m_WIN2_MST2_EN;
+                if (area_id == 3)
+                        area_status = win_ctrl & m_WIN2_MST3_EN;
+                break;
+        case 3:
+                win_ctrl = lcdc_readl(lcdc_dev, WIN3_CTRL0);
+                if (area_id == 0)
+                        area_status = win_ctrl & m_WIN3_MST0_EN;
+                if (area_id == 1)
+                        area_status = win_ctrl & m_WIN3_MST1_EN;
+                if (area_id == 2)
+                        area_status = win_ctrl & m_WIN3_MST2_EN;
+                if (area_id == 3)
+                        area_status = win_ctrl & m_WIN3_MST3_EN;
+                break;
+        case 4:
+                win_ctrl = lcdc_readl(lcdc_dev, HWC_CTRL0);
+                area_status = win_ctrl & m_HWC_EN;
+                break;
+        default:
+                pr_err("!!!%s,win[%d]area[%d],unsupport!!!\n",__func__,win_id,area_id);
+                break;
+        }
+       return area_status;
+}
+
+static int rk3368_lcdc_get_area_num(struct rk_lcdc_driver *dev_drv,
+                                          unsigned int *area_support)
+{
+        area_support[0] = 1;
+        area_support[1] = 1;
+        area_support[2] = 4;
+        area_support[3] = 4;
+
+        return 0;
 }
 
 /*overlay will be do at regupdate*/
@@ -3583,7 +3904,7 @@ static int rk3368_lcdc_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps,
        pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk));
        lcdc_dev->pixclock = pixclock;
        dev_drv->pixclock = lcdc_dev->pixclock;
-       fps = rk_fb_calc_fps(lcdc_dev->screen, pixclock);
+       fps = rk_fb_calc_fps(screen, pixclock);
        screen->ft = 1000 / fps;        /*one frame time in ms */
 
        if (set)
@@ -3768,42 +4089,70 @@ int rk3368_lcdc_poll_vblank(struct rk_lcdc_driver *dev_drv)
 }
 
 static int rk3368_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
-                                   unsigned int *dsp_addr)
+                                   unsigned int dsp_addr[][4])
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
-               dsp_addr[0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
-               dsp_addr[1] = lcdc_readl(lcdc_dev, WIN1_YRGB_MST);
-               dsp_addr[2] = lcdc_readl(lcdc_dev, WIN2_MST0);
-               dsp_addr[3] = lcdc_readl(lcdc_dev, WIN3_MST0);
+               dsp_addr[0][0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
+               dsp_addr[1][0] = lcdc_readl(lcdc_dev, WIN1_YRGB_MST);
+               dsp_addr[2][0] = lcdc_readl(lcdc_dev, WIN2_MST0);
+               dsp_addr[2][1] = lcdc_readl(lcdc_dev, WIN2_MST1);
+               dsp_addr[2][2] = lcdc_readl(lcdc_dev, WIN2_MST2);
+               dsp_addr[2][3] = lcdc_readl(lcdc_dev, WIN2_MST3);
+               dsp_addr[3][0] = lcdc_readl(lcdc_dev, WIN3_MST0);
+               dsp_addr[3][1] = lcdc_readl(lcdc_dev, WIN3_MST1);
+               dsp_addr[3][2] = lcdc_readl(lcdc_dev, WIN3_MST2);
+               dsp_addr[3][3] = lcdc_readl(lcdc_dev, WIN3_MST3);
        }
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
 }
+static u32 pwm_period_hpr, pwm_duty_lpr;
+static u32 cabc_status = 0;
 
-static struct lcdc_cabc_mode cabc_mode[4] = {
-       /* pixel_num,8 stage_up, stage_down */
-       {5, 282, 171, 300},     /*mode 1 */
-       {10, 282, 171, 300},    /*mode 2 */
-       {15, 282, 171, 300},    /*mode 3 */
-       {20, 282, 171, 300},    /*mode 4 */
-};
+int rk3368_lcdc_update_pwm(int bl_pwm_period, int bl_pwm_duty)
+{
+       pwm_period_hpr = bl_pwm_period;
+       pwm_duty_lpr = bl_pwm_duty;
+       /*pr_info("bl_pwm_period_hpr = 0x%x, bl_pwm_duty_lpr = 0x%x\n",
+       bl_pwm_period, bl_pwm_duty);*/
+       return 0;
+}
 
-static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
+int rk3368_lcdc_cabc_status(void)
+{
+       return cabc_status;
+}
+
+static int rk3368_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;
        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;
+       int *cabc_lut = NULL;
+
+       if (!screen->cabc_lut) {
+               pr_err("screen cabc lut not config, so not open cabc\n");
+               return 0;
+       } else {
+               cabc_lut = screen->cabc_lut;
+       }
 
+       if (!screen->cabc_gamma_base) {
+               pr_err("screen cabc_gamma_base no config, so not open cabc\n");
+               return 0;
+       }
        dev_drv->cabc_mode = mode;
        cabc_en = (mode > 0) ? 1 : 0;
-
+       rk3368_lcdc_get_backlight_device(dev_drv);
        if (cabc_en == 0) {
                spin_lock(&lcdc_dev->reg_lock);
                if (lcdc_dev->clk_on) {
@@ -3811,20 +4160,31 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                                     m_CABC_EN, v_CABC_EN(0));
                        lcdc_cfg_done(lcdc_dev);
                }
+               pr_info("mode = 0, close cabc\n");
+               rk_pwm_set(pwm_period_hpr, pwm_duty_lpr);
+               cabc_status = 0;
                spin_unlock(&lcdc_dev->reg_lock);
                return 0;
        }
+       if (cabc_status == 0) { /*get from pwm*/
+               rk_pwm_get(&pwm_period_hpr, &pwm_duty_lpr);
+               pr_info("pwm_period_hpr=0x%x, pwm_duty_lpr=0x%x\n",
+                       pwm_period_hpr, pwm_duty_lpr);
+       }
 
        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;
-       global_su = cabc_mode[mode - 1].global_su;
+       stage_up = up;
+       stage_down = down;
+       global_su = global;
+       pr_info("enable cabc:mode=%d, calc=%d, up=%d, down=%d, global=%d\n",
+               mode, calc, stage_up, stage_down, global_su);
 
        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);
+       gamma_global_su_rec = cabc_lut[global_su_rec];
 
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
@@ -3834,7 +4194,7 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                lcdc_msk_reg(lcdc_dev, CABC_CTRL0, mask, val);
 
                mask = m_CABC_TOTAL_PIXEL_NUM | m_CABC_LUT_EN;
-               val = v_CABC_TOTAL_PIXEL_NUM(total_pixel) | v_CABC_LUT_EN(0);
+               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 +4202,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 |
@@ -3853,6 +4213,7 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                lcdc_msk_reg(lcdc_dev, CABC_CTRL3, mask, val);
                lcdc_cfg_done(lcdc_dev);
        }
+       cabc_status = 1;
        spin_unlock(&lcdc_dev->reg_lock);
 
        return 0;
@@ -4041,7 +4402,8 @@ static int rk3368_lcdc_set_bcsh(struct rk_lcdc_driver *dev_drv, bool enable)
        return 0;
 }
 
-static int rk3368_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
+static int __maybe_unused
+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);
@@ -4099,10 +4461,20 @@ static int rk3368_lcdc_backlight_close(struct rk_lcdc_driver *dev_drv,
        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,
@@ -4112,12 +4484,14 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .suspend = rk3368_lcdc_early_suspend,
        .resume = rk3368_lcdc_early_resume,
        .get_win_state = rk3368_lcdc_get_win_state,
+       .area_support_num = rk3368_lcdc_get_area_num,
        .ovl_mgr = rk3368_lcdc_ovl_mgr,
        .get_disp_info = rk3368_lcdc_get_disp_info,
        .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_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,
@@ -4132,9 +4506,10 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .dump_reg = rk3368_lcdc_reg_dump,
        .cfg_done = rk3368_lcdc_config_done,
        .set_irq_to_cpu = rk3368_lcdc_set_irq_to_cpu,
-       .dsp_black = rk3368_lcdc_dsp_black,
+       /*.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
@@ -4179,7 +4554,10 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
        struct lcdc_device *lcdc_dev = (struct lcdc_device *)dev_id;
        ktime_t timestamp = ktime_get();
        u32 intr_status;
-
+       u32 scale_global_limit, scale_global_limit_reg;
+       u32 cabc_pwm_lut_value;
+       int pwm_plus;
+       int *cabc_gamma_base = NULL;
        intr_status = lcdc_readl(lcdc_dev, INTR_STATUS);
 
        if (intr_status & m_FS_INTR_STS) {
@@ -4197,13 +4575,34 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
 #endif
                lcdc_dev->driver.vsync_info.timestamp = timestamp;
                wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
-
        } else if (intr_status & m_LINE_FLAG0_INTR_STS) {
                lcdc_dev->driver.frame_time.last_framedone_t =
-                   lcdc_dev->driver.frame_time.framedone_t;
+                       lcdc_dev->driver.frame_time.framedone_t;
                lcdc_dev->driver.frame_time.framedone_t = cpu_clock(0);
                lcdc_msk_reg(lcdc_dev, INTR_CLEAR, m_LINE_FLAG0_INTR_CLR,
                             v_LINE_FLAG0_INTR_CLR(1));
+
+               if (cabc_status == 1) {
+                       cabc_gamma_base =
+                               lcdc_dev->driver.cur_screen->cabc_gamma_base;
+                       scale_global_limit  = lcdc_readl(lcdc_dev, CABC_DEBUG2);
+                       scale_global_limit_reg = scale_global_limit;
+                       scale_global_limit >>= 16;
+                       scale_global_limit &= 0xff;
+
+                       if (lcdc_dev->driver.cabc_pwm_pol == 1) {/*negative*/
+                               pwm_plus = pwm_period_hpr - pwm_duty_lpr;
+                               cabc_pwm_lut_value =
+                                       pwm_period_hpr -
+                                       ((cabc_gamma_base[scale_global_limit] * pwm_plus) >> 16);
+                       } else {/*positive*/
+                               pwm_plus = pwm_duty_lpr;
+                               cabc_pwm_lut_value =
+                                       cabc_gamma_base[scale_global_limit] *
+                                       pwm_plus >> 16;
+                       }
+                       rk_pwm_set(pwm_period_hpr, cabc_pwm_lut_value);
+               }
        } else if (intr_status & m_LINE_FLAG1_INTR_STS) {
                /*line flag1 */
                lcdc_msk_reg(lcdc_dev, INTR_CLEAR, m_LINE_FLAG1_INTR_CLR,
@@ -4349,6 +4748,7 @@ 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)) {
@@ -4356,11 +4756,19 @@ static int rk3368_lcdc_probe(struct platform_device *pdev)
                return PTR_ERR(lcdc_dev->grf_base);
        }
        lcdc_dev->pmugrf_base =
-               syscon_regmap_lookup_by_phandle(np, "rockchip,pmu");
+               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->cru_base =
+               syscon_regmap_lookup_by_phandle(np, "rockchip,cru");
+       if (IS_ERR(lcdc_dev->cru_base)) {
+               dev_err(&pdev->dev, "can't find lcdc cru_base property\n");
+               return PTR_ERR(lcdc_dev->cru_base);
+       }
+
        lcdc_dev->id = 0;
        dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id);
        dev_drv = &lcdc_dev->driver;
@@ -4369,6 +4777,7 @@ static int rk3368_lcdc_probe(struct platform_device *pdev)
        dev_drv->id = lcdc_dev->id;
        dev_drv->ops = &lcdc_drv_ops;
        dev_drv->lcdc_win_num = ARRAY_SIZE(lcdc_win);
+       dev_drv->reserved_fb = 1;/*only need reserved 1 buffer*/
        spin_lock_init(&lcdc_dev->reg_lock);
 
        lcdc_dev->irq = platform_get_irq(pdev, 0);
@@ -4417,9 +4826,23 @@ static int rk3368_lcdc_remove(struct platform_device *pdev)
 static void rk3368_lcdc_shutdown(struct platform_device *pdev)
 {
        struct lcdc_device *lcdc_dev = platform_get_drvdata(pdev);
+       struct rk_lcdc_driver *dev_drv = &lcdc_dev->driver;
+#if 1
+       dev_drv->suspend_flag = 1;
+       mdelay(100);
+       flush_kthread_worker(&dev_drv->update_regs_worker);
+       kthread_stop(dev_drv->update_regs_thread);
+       rk3368_lcdc_deint(lcdc_dev);
+       if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+               dev_drv->trsm_ops->disable();
 
+       rk3368_lcdc_clk_disable(lcdc_dev);
+       rk_disp_pwr_disable(dev_drv);
+#else
        rk3368_lcdc_early_suspend(&lcdc_dev->driver);
        rk3368_lcdc_deint(lcdc_dev);
+#endif
+
 }
 
 #if defined(CONFIG_OF)