video: rockchip: vop: 3399: fix afbdc abnormal
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / lcdc / rk3036_lcdc.c
old mode 100644 (file)
new mode 100755 (executable)
index 6f36d9c..dbaf15b
@@ -34,8 +34,7 @@
 #include <linux/rockchip/common.h>
 #include <dt-bindings/clock/rk_system_status.h>
 #if defined(CONFIG_ION_ROCKCHIP)
-#include <linux/rockchip/iovmm.h>
-#include <linux/rockchip/sysmmu.h>
+#include <linux/rockchip-iovmm.h>
 #endif
 #include "rk3036_lcdc.h"
 
@@ -146,7 +145,7 @@ static int rk3036_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv)
        lcdc_msk_reg(lcdc_dev, INT_STATUS, mask, val);
        return 0;
 }
-
+/*
 static int rk3036_lcdc_disable_irq(struct lcdc_device *lcdc_dev)
 {
        u32 mask, val;
@@ -162,7 +161,7 @@ static int rk3036_lcdc_disable_irq(struct lcdc_device *lcdc_dev)
        }
        mdelay(1);
        return 0;
-}
+}*/
 
 static void rk_lcdc_read_reg_defalut_cfg(struct lcdc_device
                                             *lcdc_dev)
@@ -171,7 +170,7 @@ static void rk_lcdc_read_reg_defalut_cfg(struct lcdc_device
        u32 value = 0;
 
        spin_lock(&lcdc_dev->reg_lock);
-       for (reg = 0; reg < 0xdc; reg += 4)
+       for (reg = 0; reg < 0xe0; reg += 4)
                value = lcdc_readl(lcdc_dev, reg);
 
        spin_unlock(&lcdc_dev->reg_lock);
@@ -181,18 +180,21 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev)
 {
        int win0_top = 0;
        u32 mask, val;
-       enum data_format win0_format = lcdc_dev->driver.win[0]->format;
-       enum data_format win1_format = lcdc_dev->driver.win[1]->format;
+       enum data_format win0_format = lcdc_dev->driver.win[0]->area[0].format;
+       enum data_format win1_format = lcdc_dev->driver.win[1]->area[0].format;
 
        int win0_alpha_en = ((win0_format == ARGB888) ||
                                (win0_format == ABGR888)) ? 1 : 0;
        int win1_alpha_en = ((win1_format == ARGB888) ||
                                (win1_format == ABGR888)) ? 1 : 0;
+       int atv_layer_cnt = lcdc_dev->driver.win[0]->state +
+                       lcdc_dev->driver.win[1]->state;
        u32 *_pv = (u32 *)lcdc_dev->regsbak;
 
        _pv += (DSP_CTRL0 >> 2);
        win0_top = ((*_pv) & (m_WIN0_TOP)) >> 8;
-       if (win0_top && (lcdc_dev->atv_layer_cnt >= 2) && (win0_alpha_en)) {
+
+       if (win0_top && (atv_layer_cnt >= 2) && (win0_alpha_en)) {
                mask =  m_WIN0_ALPHA_EN | m_WIN1_ALPHA_EN |
                        m_WIN1_PREMUL_SCALE;
                val = v_WIN0_ALPHA_EN(1) | v_WIN1_ALPHA_EN(0) |
@@ -204,7 +206,7 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev)
                val = v_WIN0_ALPHA_MODE(1) | v_PREMUL_ALPHA_ENABLE(1) |
                        v_ALPHA_MODE_SEL1(0);
                lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val);
-       } else if ((!win0_top) && (lcdc_dev->atv_layer_cnt >= 2) &&
+       } else if ((!win0_top) && (atv_layer_cnt >= 2) &&
                   (win1_alpha_en)) {
                mask =  m_WIN0_ALPHA_EN | m_WIN1_ALPHA_EN |
                        m_WIN1_PREMUL_SCALE;
@@ -222,6 +224,21 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev)
                val = v_WIN0_ALPHA_EN(0) | v_WIN1_ALPHA_EN(0);
                lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val);
        }
+
+       if (lcdc_dev->driver.win[2]->state == 1) {
+               mask =  m_HWC_ALPAH_EN;
+               val = v_HWC_ALPAH_EN(1);
+               lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val);
+
+               mask =  m_HWC_ALPHA_MODE;
+               val = v_HWC_ALPHA_MODE(1);
+               lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val);
+       } else {
+               mask =  m_HWC_ALPAH_EN;
+               val = v_HWC_ALPAH_EN(0);
+               lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val);
+       }
+
        return 0;
 }
 
@@ -229,15 +246,15 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                                   struct rk_lcdc_win *win)
 {
        u32 mask, val;
+       int hwc_size;
 
        if (win->state == 1) {
                if (win->id == 0) {
                        mask = m_WIN0_EN | m_WIN0_FORMAT | m_WIN0_RB_SWAP;
                        val = v_WIN0_EN(win->state) |
-                             v_WIN0_FORMAT(win->fmt_cfg) |
-                             v_WIN0_RB_SWAP(win->swap_rb);
+                             v_WIN0_FORMAT(win->area[0].fmt_cfg) |
+                             v_WIN0_RB_SWAP(win->area[0].swap_rb);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
-
                        lcdc_writel(lcdc_dev, WIN0_SCL_FACTOR_YRGB,
                                    v_X_SCL_FACTOR(win->scale_yrgb_x) |
                                    v_Y_SCL_FACTOR(win->scale_yrgb_y));
@@ -255,8 +272,8 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                                    v_DSP_STX(win->area[0].dsp_stx) |
                                    v_DSP_STY(win->area[0].dsp_sty));
                        lcdc_writel(lcdc_dev, WIN0_DSP_INFO,
-                                   v_DSP_WIDTH(win->area[0].xsize) |
-                                   v_DSP_HEIGHT(win->area[0].ysize));
+                                   v_DSP_WIDTH(win->post_cfg.xsize) |
+                                   v_DSP_HEIGHT(win->post_cfg.ysize));
 
                        lcdc_writel(lcdc_dev, WIN0_YRGB_MST,
                                    win->area[0].y_addr);
@@ -265,10 +282,9 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                } else if (win->id == 1) {
                        mask = m_WIN1_EN | m_WIN1_FORMAT | m_WIN1_RB_SWAP;
                        val = v_WIN1_EN(win->state) |
-                             v_WIN1_FORMAT(win->fmt_cfg) |
-                             v_WIN1_RB_SWAP(win->swap_rb);
+                             v_WIN1_FORMAT(win->area[0].fmt_cfg) |
+                             v_WIN1_RB_SWAP(win->area[0].swap_rb);
                        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
-
                        lcdc_writel(lcdc_dev, WIN1_SCL_FACTOR_YRGB,
                                    v_X_SCL_FACTOR(win->scale_yrgb_x) |
                                    v_Y_SCL_FACTOR(win->scale_yrgb_y));
@@ -279,26 +295,52 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                                    v_ACT_WIDTH(win->area[0].xact) |
                                    v_ACT_HEIGHT(win->area[0].yact));
                        lcdc_writel(lcdc_dev, WIN1_DSP_INFO,
-                                   v_DSP_WIDTH(win->area[0].xsize) |
-                                   v_DSP_HEIGHT(win->area[0].ysize));
+                                   v_DSP_WIDTH(win->post_cfg.xsize) |
+                                   v_DSP_HEIGHT(win->post_cfg.ysize));
                        lcdc_writel(lcdc_dev, WIN1_DSP_ST,
                                    v_DSP_STX(win->area[0].dsp_stx) |
                                    v_DSP_STY(win->area[0].dsp_sty));
                        lcdc_writel(lcdc_dev, WIN1_MST, win->area[0].y_addr);
-               } /* else if (win->id == 2) {
-               }*/
+               } else if (win->id == 2) {
+                       mask = m_HWC_EN | m_HWC_LODAD_EN;
+                       val = v_HWC_EN(win->state) | v_HWC_LODAD_EN(1);
+                       lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
+                       if ((win->area[0].xsize == 32) &&
+                           (win->area[0].ysize == 32))
+                               hwc_size = 0;
+                       else if ((win->area[0].xsize == 64) &&
+                                (win->area[0].ysize == 64))
+                               hwc_size = 1;
+                       else
+                               dev_err(lcdc_dev->dev,
+                                       "unsupport hwc size:x=%d,y=%d\n",
+                                       win->area[0].xsize,
+                                       win->area[0].ysize);
+                       lcdc_writel(lcdc_dev, HWC_DSP_ST,
+                                   v_DSP_STX(win->area[0].dsp_stx) |
+                                   v_DSP_STY(win->area[0].dsp_sty));
+                       lcdc_writel(lcdc_dev, HWC_MST, win->area[0].y_addr);
+               }
        } else {
                win->area[0].y_addr = 0;
                win->area[0].uv_addr = 0;
-               if (win->id == 0)
+               if (win->id == 0) {
                        lcdc_msk_reg(lcdc_dev,
                                     SYS_CTRL, m_WIN0_EN, v_WIN0_EN(0));
-               else if (win->id == 1)
+                       lcdc_writel(lcdc_dev, WIN0_YRGB_MST,
+                                   win->area[0].y_addr);
+                       lcdc_writel(lcdc_dev, WIN0_CBR_MST,
+                                   win->area[0].uv_addr);
+               } else if (win->id == 1) {
                        lcdc_msk_reg(lcdc_dev,
                                     SYS_CTRL, m_WIN1_EN, v_WIN1_EN(0));
-               else if (win->id == 2)
+                       lcdc_writel(lcdc_dev, WIN1_MST, win->area[0].y_addr);
+               } else if (win->id == 2) {
                        lcdc_msk_reg(lcdc_dev,
-                                    SYS_CTRL, m_HWC_EN, v_HWC_EN(0));
+                                    SYS_CTRL, m_HWC_EN | m_HWC_LODAD_EN,
+                                    v_HWC_EN(0) | v_HWC_LODAD_EN(0));
+                       lcdc_writel(lcdc_dev, HWC_MST, win->area[0].y_addr);
+               }
        }
        rk3036_lcdc_alpha_cfg(lcdc_dev);
 }
@@ -315,9 +357,9 @@ static void lcdc_layer_enable(struct lcdc_device *lcdc_dev,
                                         "wakeup from standby!\n");
                                lcdc_dev->standby = 0;
                        }
-                       lcdc_dev->atv_layer_cnt++;
-               } else if ((lcdc_dev->atv_layer_cnt > 0) && (!open)) {
-                       lcdc_dev->atv_layer_cnt--;
+                       lcdc_dev->atv_layer_cnt |= (1 << win_id);
+               } else if ((lcdc_dev->atv_layer_cnt & (1 << win_id)) && (!open)) {
+                       lcdc_dev->atv_layer_cnt &= ~(1 << win_id);
                }
                lcdc_dev->driver.win[win_id]->state = open;
                if (!open) {
@@ -334,7 +376,7 @@ static void lcdc_layer_enable(struct lcdc_device *lcdc_dev,
        }
        spin_unlock(&lcdc_dev->reg_lock);
 }
-
+/*
 static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
 {
        struct lcdc_device *lcdc_dev =
@@ -354,7 +396,6 @@ static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
                lcdc_cfg_done(lcdc_dev);
        }
        spin_unlock(&lcdc_dev->reg_lock);
-       /* if (dev_drv->wait_fs) { */
        if (0) {
                spin_lock_irqsave(&dev_drv->cpl_lock, flags);
                init_completion(&dev_drv->frame_done);
@@ -372,10 +413,10 @@ static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
        DBG(2, "%s for lcdc%d\n", __func__, lcdc_dev->id);
        return 0;
 }
-
+*/
 static void rk3036_lcdc_reg_restore(struct lcdc_device *lcdc_dev)
 {
-       memcpy((u8 *)lcdc_dev->regs, (u8 *)lcdc_dev->regsbak, 0xdc);
+       memcpy((u8 *)lcdc_dev->regs, (u8 *)lcdc_dev->regsbak, 0xe0);
 }
 
 static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
@@ -384,7 +425,7 @@ static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
 
-       spin_lock(&lcdc_dev->reg_lock);
+       /*spin_lock(&lcdc_dev->reg_lock);*/
        if (likely(lcdc_dev->clk_on)) {
                mask = m_MMU_EN | m_AXI_MAX_OUTSTANDING_EN |
                        m_AXI_OUTSTANDING_MAX_NUM;
@@ -392,9 +433,40 @@ static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
                        v_AXI_MAX_OUTSTANDING_EN(1);
                lcdc_msk_reg(lcdc_dev, AXI_BUS_CTRL, mask, val);
        }
+       /*spin_unlock(&lcdc_dev->reg_lock);*/
+}
+
+static int rk3036_lcdc_set_hwc_lut(struct rk_lcdc_driver *dev_drv,
+                                  int *hwc_lut, int mode)
+{
+       int i = 0;
+       int __iomem *c;
+       int v;
+       int len = 256*4;
+
+       struct lcdc_device *lcdc_dev =
+                       container_of(dev_drv, struct lcdc_device, driver);
+       if (dev_drv->hwc_lut == NULL)
+               dev_drv->hwc_lut = devm_kzalloc(lcdc_dev->dev, len, GFP_KERNEL);
+
+       spin_lock(&lcdc_dev->reg_lock);
+       lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_HWC_LUT_EN, v_HWC_LUT_EN(0));
+       lcdc_cfg_done(lcdc_dev);
+       mdelay(25);
+       for (i = 0; i < 256; i++) {
+               if (mode == 1)
+                       dev_drv->hwc_lut[i] = hwc_lut[i];
+               v = dev_drv->hwc_lut[i];
+               c = lcdc_dev->hwc_lut_addr_base + i;
+               writel_relaxed(v, c);
+       }
+       lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_HWC_LUT_EN, v_HWC_LUT_EN(1));
+       lcdc_cfg_done(lcdc_dev);
        spin_unlock(&lcdc_dev->reg_lock);
+       return 0;
 }
 
+#if 0
 static int rk3036_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
 {
 #ifdef CONFIG_RK_FPGA
@@ -419,7 +491,7 @@ static int rk3036_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
                 lcdc_dev->driver.name, clk_get_rate(lcdc_dev->dclk), fps);
        return 0;
 }
-
+#endif
 /********do basic init*********/
 static int rk3036_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 {
@@ -444,6 +516,9 @@ static int rk3036_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
 
        /*backup reg config at uboot*/
        rk_lcdc_read_reg_defalut_cfg(lcdc_dev);
+       if (lcdc_readl(lcdc_dev, AXI_BUS_CTRL) & m_TVE_DAC_DCLK_EN)
+               dev_drv->cur_screen->type = SCREEN_TVOUT;
+
        lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_AUTO_GATING_EN,
                     v_AUTO_GATING_EN(0));
        lcdc_cfg_done(lcdc_dev);
@@ -551,7 +626,7 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                    v_HASP(screen->mode.hsync_len + left_margin);
                lcdc_writel(lcdc_dev, DSP_HACT_ST_END, val);
 
-               if (screen->mode.vmode == FB_VMODE_INTERLACED) {
+               if (screen->mode.vmode & FB_VMODE_INTERLACED) {
                        /*First Field Timing*/
                        lcdc_writel(lcdc_dev, DSP_VTOTAL_VS_END,
                                    v_VSYNC(screen->mode.vsync_len) |
@@ -581,13 +656,19 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
 
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL0,
                                     m_INTERLACE_DSP_EN |
+                                    m_INTERLACE_DSP_POL |
                                     m_WIN1_DIFF_DCLK_EN |
                                     m_WIN0_YRGB_DEFLICK_EN |
-                                    m_WIN0_CBR_DEFLICK_EN,
+                                    m_WIN0_CBR_DEFLICK_EN |
+                                    m_WIN0_INTERLACE_EN |
+                                    m_WIN1_INTERLACE_EN,
                                     v_INTERLACE_DSP_EN(1) |
+                                    v_INTERLACE_DSP_POL(0) |
                                     v_WIN1_DIFF_DCLK_EN(1) |
                                     v_WIN0_YRGB_DEFLICK_EN(1) |
-                                    v_WIN0_CBR_DEFLICK_EN(1));
+                                    v_WIN0_CBR_DEFLICK_EN(1) |
+                                    v_WIN0_INTERLACE_EN(1) |
+                                    v_WIN1_INTERLACE_EN(1));
                } else {
                        val = v_VSYNC(screen->mode.vsync_len) |
                              v_VERPRD(screen->mode.vsync_len + upper_margin +
@@ -604,11 +685,15 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                                     m_INTERLACE_DSP_EN |
                                     m_WIN1_DIFF_DCLK_EN |
                                     m_WIN0_YRGB_DEFLICK_EN |
-                                    m_WIN0_CBR_DEFLICK_EN,
+                                    m_WIN0_CBR_DEFLICK_EN |
+                                    m_WIN0_INTERLACE_EN |
+                                    m_WIN1_INTERLACE_EN,
                                     v_INTERLACE_DSP_EN(0) |
                                     v_WIN1_DIFF_DCLK_EN(0) |
                                     v_WIN0_YRGB_DEFLICK_EN(0) |
-                                    v_WIN0_CBR_DEFLICK_EN(0));
+                                    v_WIN0_CBR_DEFLICK_EN(0) |
+                                    v_WIN0_INTERLACE_EN(1) |
+                                    v_WIN1_INTERLACE_EN(1));
                }
        }
        spin_unlock(&lcdc_dev->reg_lock);
@@ -643,15 +728,14 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
        if ((open) && (!lcdc_dev->atv_layer_cnt)) {
                rk3036_lcdc_pre_init(dev_drv);
                rk3036_lcdc_clk_enable(lcdc_dev);
-               #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (!dev_drv->mmu_dev) {
                                dev_drv->mmu_dev =
-                               rockchip_get_sysmmu_device_by_compatible(
+                               rk_fb_get_sysmmu_device_by_compatible(
                                        dev_drv->mmu_dts_name);
                                if (dev_drv->mmu_dev) {
-                                       platform_set_sysmmu(dev_drv->mmu_dev,
-                                                           dev_drv->dev);
+                                       rk_fb_platform_set_sysmmu(dev_drv->mmu_dev,
+                                                                 dev_drv->dev);
                                } else {
                                        dev_err(dev_drv->dev,
                                                "failed to get iommu device\n"
@@ -659,14 +743,12 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                                        return -1;
                                }
                        }
-                       iovmm_activate(dev_drv->dev);
                }
-               #endif
                rk3036_lcdc_reg_restore(lcdc_dev);
-               if (dev_drv->iommu_enabled)
-                       rk3036_lcdc_mmu_en(dev_drv);
+               /*if (dev_drv->iommu_enabled)
+                       rk3036_lcdc_mmu_en(dev_drv);*/
                if ((support_uboot_display() && (lcdc_dev->prop == PRMRY))) {
-                       rk3036_lcdc_set_dclk(dev_drv);
+                       /*rk3036_lcdc_set_dclk(dev_drv);*/
                        rk3036_lcdc_enable_irq(dev_drv);
                } else {
                        rk3036_load_screen(dev_drv, 1);
@@ -679,18 +761,17 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                dev_err(lcdc_dev->dev, "invalid win id:%d\n", win_id);
 
        /*when all layer closed,disable clk */
+/*
        if ((!open) && (!lcdc_dev->atv_layer_cnt)) {
                rk3036_lcdc_disable_irq(lcdc_dev);
                rk3036_lcdc_reg_update(dev_drv);
-               #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (dev_drv->mmu_dev)
-                               iovmm_deactivate(dev_drv->dev);
+                               rockchip_iovmm_deactivate(dev_drv->dev);
                }
-               #endif
                rk3036_lcdc_clk_disable(lcdc_dev);
        }
-
+*/
        return 0;
 }
 
@@ -711,56 +792,73 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id)
                win = dev_drv->win[0];
        } else if (win_id == 1) {
                win = dev_drv->win[1];
+       } else if (win_id == 2) {
+               win = dev_drv->win[2];
        } else {
                dev_err(dev_drv->dev, "un supported win number:%d\n", win_id);
                return -EINVAL;
        }
 
        spin_lock(&lcdc_dev->reg_lock);
-       win->area[0].dsp_stx = win->area[0].xpos +
-                               screen->mode.left_margin +
+       win->post_cfg.xpos = win->area[0].xpos * (dev_drv->overscan.left +
+               dev_drv->overscan.right)/200 + screen->mode.xres *
+                       (100 - dev_drv->overscan.left) / 200;
+
+       win->post_cfg.ypos = win->area[0].ypos * (dev_drv->overscan.top +
+               dev_drv->overscan.bottom)/200 +
+               screen->mode.yres *
+                       (100 - dev_drv->overscan.top) / 200;
+       win->post_cfg.xsize = win->area[0].xsize *
+                               (dev_drv->overscan.left +
+                               dev_drv->overscan.right)/200;
+       win->post_cfg.ysize = win->area[0].ysize *
+                               (dev_drv->overscan.top +
+                               dev_drv->overscan.bottom)/200;
+
+       win->area[0].dsp_stx = win->post_cfg.xpos + screen->mode.left_margin +
                                screen->mode.hsync_len;
-       if (screen->mode.vmode == FB_VMODE_INTERLACED) {
-               win->area[0].ysize /= 2;
-               win->area[0].dsp_sty = win->area[0].ypos/2 +
+       if (screen->mode.vmode & FB_VMODE_INTERLACED) {
+               win->post_cfg.ysize /= 2;
+               win->area[0].dsp_sty = win->post_cfg.ypos/2 +
                                        screen->mode.upper_margin +
                                        screen->mode.vsync_len;
        } else {
-               win->area[0].dsp_sty = win->area[0].ypos +
+               win->area[0].dsp_sty = win->post_cfg.ypos +
                                        screen->mode.upper_margin +
                                        screen->mode.vsync_len;
        }
-       win->scale_yrgb_x = calscale(win->area[0].xact, win->area[0].xsize);
-       win->scale_yrgb_y = calscale(win->area[0].yact, win->area[0].ysize);
-       switch (win->format) {
+       win->scale_yrgb_x = calscale(win->area[0].xact, win->post_cfg.xsize);
+       win->scale_yrgb_y = calscale(win->area[0].yact, win->post_cfg.ysize);
+
+       switch (win->area[0].format) {
        case ARGB888:
-               win->fmt_cfg = VOP_FORMAT_ARGB888;
-               win->swap_rb = 0;
+               win->area[0].fmt_cfg = VOP_FORMAT_ARGB888;
+               win->area[0].swap_rb = 0;
                break;
        case XBGR888:
-               win->fmt_cfg = VOP_FORMAT_ARGB888;
-               win->swap_rb = 1;
+               win->area[0].fmt_cfg = VOP_FORMAT_ARGB888;
+               win->area[0].swap_rb = 1;
                break;
        case ABGR888:
-               win->fmt_cfg = VOP_FORMAT_ARGB888;
-               win->swap_rb = 1;
+               win->area[0].fmt_cfg = VOP_FORMAT_ARGB888;
+               win->area[0].swap_rb = 1;
                break;
        case RGB888:
-               win->fmt_cfg = VOP_FORMAT_RGB888;
-               win->swap_rb = 0;
+               win->area[0].fmt_cfg = VOP_FORMAT_RGB888;
+               win->area[0].swap_rb = 0;
                break;
        case RGB565:
-               win->fmt_cfg = VOP_FORMAT_RGB565;
-               win->swap_rb = 0;
+               win->area[0].fmt_cfg = VOP_FORMAT_RGB565;
+               win->area[0].swap_rb = 0;
                break;
        case YUV444:
                if (win_id == 0) {
-                       win->fmt_cfg = VOP_FORMAT_YCBCR444;
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR444;
                        win->scale_cbcr_x = calscale(win->area[0].xact,
-                                                    win->area[0].xsize);
+                                                    win->post_cfg.xsize);
                        win->scale_cbcr_y = calscale(win->area[0].yact,
-                                                    win->area[0].ysize);
-                       win->swap_rb = 0;
+                                                    win->post_cfg.ysize);
+                       win->area[0].swap_rb = 0;
                } else {
                        dev_err(lcdc_dev->driver.dev,
                                "%s:un supported format!\n",
@@ -769,12 +867,12 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id)
                break;
        case YUV422:
                if (win_id == 0) {
-                       win->fmt_cfg = VOP_FORMAT_YCBCR422;
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR422;
                        win->scale_cbcr_x = calscale((win->area[0].xact / 2),
-                                                    win->area[0].xsize);
+                                                    win->post_cfg.xsize);
                        win->scale_cbcr_y = calscale(win->area[0].yact,
-                                                    win->area[0].ysize);
-                       win->swap_rb = 0;
+                                                    win->post_cfg.ysize);
+                       win->area[0].swap_rb = 0;
                } else {
                        dev_err(lcdc_dev->driver.dev,
                                "%s:un supported format!\n",
@@ -783,12 +881,12 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id)
                break;
        case YUV420:
                if (win_id == 0) {
-                       win->fmt_cfg = VOP_FORMAT_YCBCR420;
+                       win->area[0].fmt_cfg = VOP_FORMAT_YCBCR420;
                        win->scale_cbcr_x = calscale(win->area[0].xact / 2,
-                                                    win->area[0].xsize);
+                                                    win->post_cfg.xsize);
                        win->scale_cbcr_y = calscale(win->area[0].yact / 2,
-                                                    win->area[0].ysize);
-                       win->swap_rb = 0;
+                                                    win->post_cfg.ysize);
+                       win->area[0].swap_rb = 0;
                } else {
                        dev_err(lcdc_dev->driver.dev,
                                "%s:un supported format!\n",
@@ -802,13 +900,13 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id)
        }
        spin_unlock(&lcdc_dev->reg_lock);
 
-       DBG(1, "lcdc%d>>%s\n"
+       DBG(2, "lcdc%d>>%s\n"
                ">>format:%s>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d\n"
                ">>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id,
-               __func__, get_format_string(win->format, fmt),
-               win->area[0].xact, win->area[0].yact, win->area[0].xsize,
-               win->area[0].ysize, win->area[0].xvir, win->area[0].yvir,
-               win->area[0].xpos, win->area[0].ypos);
+               __func__, get_format_string(win->area[0].format, fmt),
+               win->area[0].xact, win->area[0].yact, win->post_cfg.xsize,
+               win->post_cfg.ysize, win->area[0].xvir, win->area[0].yvir,
+               win->post_cfg.xpos, win->post_cfg.ypos);
        return 0;
 }
 
@@ -828,6 +926,8 @@ static int rk3036_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id)
                win = dev_drv->win[0];
        } else if (win_id == 1) {
                win = dev_drv->win[1];
+       } else if (win_id == 2) {
+               win = dev_drv->win[2];
        } else {
                dev_err(dev_drv->dev, "invalid win number:%d!\n", win_id);
                return -EINVAL;
@@ -907,7 +1007,8 @@ static int rk3036_lcdc_get_win_id(struct rk_lcdc_driver *dev_drv,
 }
 
 static int rk3036_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv,
-                                    int win_id)
+                                    int win_id,
+                                    int area_id)
 {
        return dev_drv->win[win_id]->state;
 }
@@ -917,13 +1018,25 @@ static int rk3036_lcdc_ovl_mgr(struct rk_lcdc_driver *dev_drv, int swap,
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
-       int ovl;
-
+       struct rk_lcdc_win *win0 = lcdc_dev->driver.win[0];
+       struct rk_lcdc_win *win1 = lcdc_dev->driver.win[1];
+       int ovl, needswap = 0;
+
+       if (!swap) {
+               if (win0->z_order >= 0 &&
+                   win1->z_order >= 0 &&
+                   win0->z_order > win1->z_order)
+                       needswap = 1;
+               else
+                       needswap = 0;
+       } else {
+               needswap = swap;
+       }
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
                if (set) {
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_WIN0_TOP,
-                                    v_WIN0_TOP(swap));
+                                    v_WIN0_TOP(needswap));
                        ovl = swap;
                } else {
                        ovl = lcdc_read_bit(lcdc_dev, DSP_CTRL0, m_WIN0_TOP);
@@ -958,12 +1071,10 @@ static int rk3036_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv)
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY,
                             v_LCDC_STANDBY(1));
                lcdc_cfg_done(lcdc_dev);
-               #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (dev_drv->mmu_dev)
-                               iovmm_deactivate(dev_drv->dev);
+                               rockchip_iovmm_deactivate(dev_drv->dev);
                }
-               #endif
                spin_unlock(&lcdc_dev->reg_lock);
        } else {
                spin_unlock(&lcdc_dev->reg_lock);
@@ -987,6 +1098,8 @@ static int rk3036_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
        if (lcdc_dev->atv_layer_cnt) {
                rk3036_lcdc_clk_enable(lcdc_dev);
                rk3036_lcdc_reg_restore(lcdc_dev);
+               /*set hwc lut*/
+               rk3036_lcdc_set_hwc_lut(dev_drv, dev_drv->hwc_lut, 0);
 
                spin_lock(&lcdc_dev->reg_lock);
 
@@ -997,7 +1110,10 @@ static int rk3036_lcdc_early_resume(struct rk_lcdc_driver *dev_drv)
                lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BLANK_EN,
                             v_BLANK_EN(0));
                lcdc_cfg_done(lcdc_dev);
-
+               if (dev_drv->iommu_enabled) {
+                       if (dev_drv->mmu_dev)
+                               rockchip_iovmm_activate(dev_drv->dev);
+               }
                spin_unlock(&lcdc_dev->reg_lock);
        }
 
@@ -1029,13 +1145,38 @@ static int rk3036_lcdc_blank(struct rk_lcdc_driver *dev_drv,
 
 static int rk3036_lcdc_cfg_done(struct rk_lcdc_driver *dev_drv)
 {
-       struct lcdc_device *lcdc_dev = container_of(dev_drv,
-                                       struct lcdc_device, driver);
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+       int i;
+       struct rk_lcdc_win *win = NULL;
 
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
+               if (dev_drv->iommu_enabled) {
+                       if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) {
+                               lcdc_dev->iommu_status = 1;
+                               if (support_uboot_display() &&
+                                   lcdc_dev->prop == PRMRY) {
+                                       lcdc_msk_reg(lcdc_dev, SYS_CTRL,
+                                                    m_WIN0_EN,
+                                                    v_WIN0_EN(0));
+                               }
+                               lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY,
+                                            v_LCDC_STANDBY(1));
+                               lcdc_cfg_done(lcdc_dev);
+                               mdelay(50);
+                               rockchip_iovmm_activate(dev_drv->dev);
+                               rk3036_lcdc_mmu_en(dev_drv);
+                       }
+               }
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY,
                             v_LCDC_STANDBY(lcdc_dev->standby));
+               for (i = 0; i < ARRAY_SIZE(lcdc_win); i++) {
+                       win = dev_drv->win[i];
+                       if ((win->state == 0) && (win->last_state == 1))
+                               lcdc_layer_update_regs(lcdc_dev, win);
+                       win->last_state = win->state;
+               }
                lcdc_cfg_done(lcdc_dev);
        }
        spin_unlock(&lcdc_dev->reg_lock);
@@ -1066,7 +1207,7 @@ static int rk3036_lcdc_get_bcsh_hue(struct rk_lcdc_driver *dev_drv,
                        break;
                case H_COS:
                        val &= m_BCSH_COS_HUE;
-                       val >>= 16;
+                       val >>= 8;
                        break;
                default:
                        break;
@@ -1109,10 +1250,10 @@ static int rk3036_lcdc_set_bcsh_bcs(struct rk_lcdc_driver *dev_drv,
                switch (mode) {
                case BRIGHTNESS:
                /*from 0 to 255,typical is 128*/
-                       if (value < 0x80)
-                               value += 0x80;
-                       else if (value >= 0x80)
-                               value = value - 0x80;
+                       if (value < 0x20)
+                               value += 0x20;
+                       else if (value >= 0x20)
+                               value = value - 0x20;
                        mask =  m_BCSH_BRIGHTNESS;
                        val = v_BCSH_BRIGHTNESS(value);
                        break;
@@ -1149,10 +1290,10 @@ static int rk3036_lcdc_get_bcsh_bcs(struct rk_lcdc_driver *dev_drv,
                switch (mode) {
                case BRIGHTNESS:
                        val &= m_BCSH_BRIGHTNESS;
-                       if (val > 0x80)
-                               val -= 0x80;
-                       else
-                               val += 0x80;
+                       if (val > 0x20)
+                               val -= 0x20;
+                       else if (val == 0x20)
+                               val = -32;
                        break;
                case CONTRAST:
                        val &= m_BCSH_CONTRAST;
@@ -1160,7 +1301,7 @@ static int rk3036_lcdc_get_bcsh_bcs(struct rk_lcdc_driver *dev_drv,
                        break;
                case SAT_CON:
                        val &= m_BCSH_SAT_CON;
-                       val >>= 20;
+                       val >>= 16;
                        break;
                default:
                        break;
@@ -1180,9 +1321,13 @@ static int rk3036_lcdc_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open)
        spin_lock(&lcdc_dev->reg_lock);
        if (lcdc_dev->clk_on) {
                if (open) {
-                       lcdc_writel(lcdc_dev, BCSH_CTRL, 0x1);
-                       lcdc_writel(lcdc_dev, BCSH_BCS, 0xd0010000);
-                       lcdc_writel(lcdc_dev, BCSH_H, 0x01000000);
+                       lcdc_writel(lcdc_dev, BCSH_CTRL,
+                                   v_BCSH_EN(1) | v_BCSH_OUT_MODE(3));
+                       lcdc_writel(lcdc_dev, BCSH_BCS,
+                                   v_BCSH_BRIGHTNESS(0x00) |
+                                   v_BCSH_CONTRAST(0x80) |
+                                   v_BCSH_SAT_CON(0x80));
+                       lcdc_writel(lcdc_dev, BCSH_H, v_BCSH_COS_HUE(0x80));
                } else {
                        mask = m_BCSH_EN;
                        val = v_BCSH_EN(0);
@@ -1194,15 +1339,45 @@ static int rk3036_lcdc_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open)
        return 0;
 }
 
-static int rk3036_fb_win_remap(struct rk_lcdc_driver *dev_drv,
-                              enum fb_win_map_order order)
+static int rk3036_lcdc_set_overscan(struct rk_lcdc_driver *dev_drv,
+                                   struct overscan *overscan)
+{
+       int i;
+
+       dev_drv->overscan = *overscan;
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               if (dev_drv->win[i] && dev_drv->win[i]->state) {
+                       rk3036_lcdc_set_par(dev_drv, i);
+                       rk3036_lcdc_pan_display(dev_drv, i);
+               }
+       }
+       rk3036_lcdc_cfg_done(dev_drv);
+       return 0;
+}
+
+static int rk3036_fb_win_remap(struct rk_lcdc_driver *dev_drv, u16 order)
 {
+       struct rk_lcdc_win_area area;
+       int fb2_win_id, fb1_win_id, fb0_win_id;
+
        mutex_lock(&dev_drv->fb_win_id_mutex);
        if (order == FB_DEFAULT_ORDER)
-               order = FB0_WIN1_FB1_WIN0_FB2_WIN2;
-       dev_drv->fb2_win_id = order / 100;
-       dev_drv->fb1_win_id = (order / 10) % 10;
-       dev_drv->fb0_win_id = order % 10;
+               order = FB0_WIN0_FB1_WIN1_FB2_WIN2;
+
+       fb2_win_id = order / 100;
+       fb1_win_id = (order / 10) % 10;
+       fb0_win_id = order % 10;
+
+       if (fb0_win_id != dev_drv->fb0_win_id) {
+               area = dev_drv->win[(int)dev_drv->fb0_win_id]->area[0];
+               dev_drv->win[(int)dev_drv->fb0_win_id]->area[0] =
+                       dev_drv->win[fb0_win_id]->area[0];
+               dev_drv->win[fb0_win_id]->area[0] = area;
+               dev_drv->fb0_win_id = fb0_win_id;
+       }
+       dev_drv->fb1_win_id = fb1_win_id;
+       dev_drv->fb2_win_id = fb2_win_id;
+
        mutex_unlock(&dev_drv->fb_win_id_mutex);
 
        return 0;
@@ -1270,14 +1445,14 @@ static int rk3036_lcdc_poll_vblank(struct rk_lcdc_driver *dev_drv)
 }
 
 static int rk3036_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);
 
        if (lcdc_dev->clk_on) {
-               dsp_addr[0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
-               dsp_addr[1] = lcdc_readl(lcdc_dev, WIN1_MST);
+               dsp_addr[0][0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST);
+               dsp_addr[1][0] = lcdc_readl(lcdc_dev, WIN1_MST);
        }
        return 0;
 }
@@ -1297,7 +1472,7 @@ static ssize_t rk3036_lcdc_get_disp_info(struct rk_lcdc_driver *dev_drv,
        }
 
        size = snprintf(buf, PAGE_SIZE, "win%d: %s\n", win_id,
-                       get_format_string(win->format, fmt));
+                       get_format_string(win->area[0].format, fmt));
        size += snprintf(buf + size, PAGE_SIZE - size,
                         "      xact %d yact %d xvir %d yvir %d\n",
                win->area[0].xact, win->area[0].yact,
@@ -1361,11 +1536,12 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .get_dsp_bcsh_hue       = rk3036_lcdc_get_bcsh_hue,
        .get_dsp_bcsh_bcs       = rk3036_lcdc_get_bcsh_bcs,
        .open_bcsh              = rk3036_lcdc_open_bcsh,
+       .set_overscan           = rk3036_lcdc_set_overscan,
+       .set_hwc_lut            = rk3036_lcdc_set_hwc_lut,
 };
 
 static int rk3036_lcdc_parse_dt(struct lcdc_device *lcdc_dev)
 {
-#if defined(CONFIG_ROCKCHIP_IOMMU)
        struct device_node *np = lcdc_dev->dev->of_node;
        int val;
 
@@ -1373,9 +1549,11 @@ static int rk3036_lcdc_parse_dt(struct lcdc_device *lcdc_dev)
                lcdc_dev->driver.iommu_enabled = 0;
        else
                lcdc_dev->driver.iommu_enabled = val;
-#else
-       lcdc_dev->driver.iommu_enabled = 0;
-#endif
+       if (of_property_read_u32(np, "rockchip,fb-win-map", &val))
+               lcdc_dev->driver.fb_win_map = FB_DEFAULT_ORDER;
+       else
+               lcdc_dev->driver.fb_win_map = val;
+
        return 0;
 }
 
@@ -1408,6 +1586,8 @@ static int rk3036_lcdc_probe(struct platform_device *pdev)
        if (IS_ERR(lcdc_dev->regsbak))
                return PTR_ERR(lcdc_dev->regsbak);
 
+       lcdc_dev->hwc_lut_addr_base = (lcdc_dev->regs + HWC_LUT_ADDR);
+       lcdc_dev->prop = PRMRY;
        dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id);
        dev_drv = &lcdc_dev->driver;
        dev_drv->dev = dev;
@@ -1434,7 +1614,7 @@ static int rk3036_lcdc_probe(struct platform_device *pdev)
        }
 
        if (dev_drv->iommu_enabled)
-               strcpy(dev_drv->mmu_dts_name, "iommu,vop_mmu");
+               strcpy(dev_drv->mmu_dts_name, VOP_IOMMU_COMPATIBLE_NAME);
 
        ret = rk_fb_register(dev_drv, lcdc_win, lcdc_dev->id);
        if (ret < 0) {
@@ -1505,4 +1685,4 @@ static void __exit rk3036_lcdc_module_exit(void)
 }
 
 fs_initcall(rk3036_lcdc_module_init);
-module_exit(rk3036_lcdc_module_exit);
\ No newline at end of file
+module_exit(rk3036_lcdc_module_exit);