rk_fb: add extern screen open iommu, when dual screen display using iommu
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
old mode 100644 (file)
new mode 100755 (executable)
index a9092a8..5a30657
@@ -61,7 +61,7 @@
 #define H_USE_FENCE 1
 /* #define FB_ROATE_BY_KERNEL 1 */
 
-static int hdmi_switch_complete;
+static int hdmi_switch_state;
 static struct platform_device *fb_pdev;
 
 #if defined(CONFIG_FB_MIRRORING)
@@ -76,6 +76,19 @@ static struct rk_fb_trsm_ops *trsm_lvds_ops;
 static struct rk_fb_trsm_ops *trsm_edp_ops;
 static struct rk_fb_trsm_ops *trsm_mipi_ops;
 static int uboot_logo_on;
+
+static int rk_fb_debug_lvl;
+static int rk_fb_iommu_debug;
+module_param(rk_fb_debug_lvl, int, S_IRUGO | S_IWUSR);
+module_param(rk_fb_iommu_debug, int, S_IRUGO | S_IWUSR);
+
+#define fb_dbg(level, x...) do {               \
+       if (unlikely(rk_fb_debug_lvl >= level)) \
+               printk(KERN_INFO x);            \
+       } while (0)
+static int rk_fb_config_debug(struct rk_lcdc_driver *dev_drv,
+                             struct rk_fb_win_cfg_data *win_data,
+                             struct rk_fb_reg_data *regs, u32 cmd);
 int support_uboot_display(void)
 {
        return uboot_logo_on;
@@ -221,7 +234,7 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
                case HAL_PIXEL_FORMAT_YCbCr_422_SP_10:  /* yuv444 */
                        fb_data_fmt = YUV422_A;
                        break;
-               case HAL_PIXEL_FORMAT_YCrCb_420_SP_10:  /* yuv444 */
+               case HAL_PIXEL_FORMAT_YCrCb_444_SP_10:  /* yuv444 */
                        fb_data_fmt = YUV444_A;
                        break;
                case HAL_PIXEL_FORMAT_FBDC_RGB565:      /* fbdc rgb565*/
@@ -452,6 +465,7 @@ int rk_fb_video_mode_from_timing(const struct display_timing *dt,
        screen->color_mode = dt->color_mode;
        screen->dsp_lut = dt->dsp_lut;
        screen->cabc_lut = dt->cabc_lut;
+       screen->cabc_gamma_base = dt->cabc_gamma_base;
 
        if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
                screen->pin_dclk = 1;
@@ -870,7 +884,8 @@ static int rk_fb_close(struct fb_info *info, int user)
 
        if (win_id >= 0) {
                win = dev_drv->win[win_id];
-               fb_par->state--;
+               if (fb_par->state)
+                       fb_par->state--;
                if (!fb_par->state) {
                        if (fb_par->fb_phy_base > 0)
                                info->fix.smem_start = fb_par->fb_phy_base;
@@ -1271,6 +1286,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var,
        u16 uv_x_off, uv_y_off, uv_y_act;
        u8 is_pic_yuv = 0;
 
+       if (dev_drv->suspend_flag)
+               return 0;
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
                return -ENODEV;
@@ -1287,8 +1304,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var,
        case YUV422_A:
                is_pic_yuv = 1;
                stride = stride_32bit_1;
-               uv_stride = stride_32bit_1 >> 1;
-               uv_x_off = xoffset >> 1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
                uv_y_off = yoffset;
                fix->line_length = stride;
                uv_y_act = win->area[0].yact >> 1;
@@ -1381,7 +1398,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var,
         /*if not want the config effect,set reserved[3] bit[0] 1*/
         if (likely((var->reserved[3] & 0x1) == 0))
                dev_drv->ops->cfg_done(dev_drv);
-
+       if (dev_drv->hdmi_switch)
+               mdelay(100);
        return 0;
 }
 
@@ -1438,7 +1456,10 @@ static int rk_fb_copy_from_loader(struct fb_info *info)
 }
 #endif
 #ifdef CONFIG_ROCKCHIP_IOMMU
-static int g_last_addr[4];
+static int g_last_addr[5][4];
+static int g_now_config_addr[5][4];
+static int g_last_state[5][4];
+static int g_now_config_state[5][4];
 int g_last_timeout;
 u32 freed_addr[10];
 u32 freed_index;
@@ -1452,17 +1473,20 @@ int rk_fb_sysmmu_fault_handler(struct device *dev,
                               unsigned long fault_addr, unsigned int status)
 {
        struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
-       int i = 0;
+       int i = 0, j = 0;
        static int page_fault_cnt;
        if ((page_fault_cnt++) >= 10)
                return 0;
        pr_err
            ("PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx),status=%d\n",
             fault_addr, pgtable_base, status);
-       printk("last config addr:\n" "win0:0x%08x\n" "win1:0x%08x\n"
-              "win2:0x%08x\n" "win3:0x%08x\n", g_last_addr[0], g_last_addr[1],
-              g_last_addr[2], g_last_addr[3]);
-       printk("last freed buffer:\n");
+       pr_info("last config addr:\n");
+       for (i = 0; i < 4; i++) {
+               for (j = 0; j < 4; j++)
+                        pr_info("win[%d],area[%d] = 0x%08x\n",
+                                i, j, g_last_addr[i][j]);
+       }
+       pr_info("last freed buffer:\n");
        for (i = 0; (freed_addr[i] != 0xfefefefe) && freed_addr[i]; i++)
                printk("%d:0x%08x\n", i, freed_addr[i]);
        printk("last timeout:%d\n", g_last_timeout);
@@ -1495,8 +1519,7 @@ void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv,
                index_buf = area_data->index_buf;
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
-                       if ((rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
-                            (area_data->ion_handle != NULL))
+                       if (area_data->ion_handle != NULL)
                                ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client,
                                                area_data->ion_handle);
                        freed_addr[freed_index++] = area_data->smem_start;
@@ -1545,6 +1568,7 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                win->alpha_mode = reg_win_data->alpha_mode;
                win->g_alpha_val = reg_win_data->g_alpha_val;
                win->mirror_en = reg_win_data->mirror_en;
+               win->colorspace = reg_win_data->colorspace;
                win->area[0].fbdc_en =
                        reg_win_data->reg_area_data[0].fbdc_en;
                win->area[0].fbdc_cor_en =
@@ -1555,14 +1579,12 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                        if (reg_win_data->reg_area_data[i].smem_start > 0) {
                                win->area[i].format =
                                        reg_win_data->reg_area_data[i].data_format;
-                               if (inf->disp_policy != DISPLAY_POLICY_BOX)
-                                       win->area[i].ion_hdl =
+                               win->area[i].ion_hdl =
                                        reg_win_data->reg_area_data[i].ion_handle;
                                win->area[i].smem_start =
                                        reg_win_data->reg_area_data[i].smem_start;
                                 if (inf->disp_mode == DUAL ||
-                                    inf->disp_mode == NO_DUAL ||
-                                    inf->disp_policy == DISPLAY_POLICY_BOX) {
+                                    inf->disp_mode == NO_DUAL) {
                                        win->area[i].xpos =
                                                reg_win_data->reg_area_data[i].xpos;
                                        win->area[i].ypos =
@@ -1590,7 +1612,7 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                                                 primary_screen.mode.yres;
 
                                        /* recalc display size if set hdmi scaler when at ONE_DUAL mode */
-                                       if (inf->disp_mode == ONE_DUAL && hdmi_switch_complete) {
+                                       if (inf->disp_mode == ONE_DUAL && hdmi_switch_state) {
                                                if (cur_screen->xsize > 0 &&
                                                    cur_screen->xsize <= cur_screen->mode.xres) {
                                                        win->area[i].xpos =
@@ -1625,15 +1647,24 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                                win->area[i].y_vir_stride =
                                    reg_win_data->reg_area_data[i].y_vir_stride;
                                win->area[i].state = 1;
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+                               if (dev_drv->iommu_enabled) {
+                                       g_now_config_addr[win->id][i] =
+                                               win->area[i].smem_start +
+                                               win->area[i].y_offset;
+                                       g_now_config_state[win->id][i] = 1;
+                               }
+#endif
                        } else {
                                win->area[i].state = 0;
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+                               if (dev_drv->iommu_enabled) {
+                                       g_now_config_addr[win->id][i] = 0;
+                                       g_now_config_state[win->id][i] = 0;
+                               }
+#endif
                        }
                }
-       } else {
-       /*
-               win->state = 0;
-               win->z_order = -1;
-       */
        }
 }
 
@@ -1652,20 +1683,123 @@ static struct rk_fb_reg_win_data *rk_fb_get_win_data(struct rk_fb_reg_data
        return win_data;
 }
 
+static int rk_fb_reg_effect(struct rk_lcdc_driver *dev_drv,
+                            struct rk_fb_reg_data *regs,
+                            int count)
+{
+       int i, j, wait_for_vsync = false;
+       unsigned int dsp_addr[5][4];
+       int win_status = 0;
+
+       if (dev_drv->ops->get_dsp_addr)
+               dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
+
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               for (j = 0;j < RK_WIN_MAX_AREA; j++) {
+                       if ((j > 0) && (dev_drv->area_support[i] == 1)) {
+                               continue;
+                       }
+                       if (dev_drv->win[i]->area[j].state == 1) {
+                               u32 new_start =
+                                       dev_drv->win[i]->area[j].smem_start +
+                                       dev_drv->win[i]->area[j].y_offset;
+                               u32 reg_start = dsp_addr[i][j];
+                               if (unlikely(new_start != reg_start)) {
+                                       wait_for_vsync = true;
+                                       dev_info(dev_drv->dev,
+                                                "win%d:new_addr:0x%08x cur_addr:0x%08x--%d\n",
+                                                i, new_start, reg_start, 101 - count);
+                                       break;
+                               }
+                       } else if (dev_drv->win[i]->area[j].state == 0) {
+                               if (dev_drv->ops->get_win_state) {
+                                       win_status =
+                                       dev_drv->ops->get_win_state(dev_drv, i, j);
+                                       if (win_status)
+                                               wait_for_vsync = true;
+                               }
+                       } else {
+                               pr_err("!!!win[%d]state:%d,error!!!\n",
+                                      i, dev_drv->win[i]->state);
+                       }
+               }
+       }
+
+       return wait_for_vsync;
+}
+
+static int rk_fb_iommu_page_fault_dump(struct rk_lcdc_driver *dev_drv)
+{
+       int i, j, state, page_fault = 0;
+       unsigned int dsp_addr[5][4];
+
+       if (dev_drv->ops->extern_func) {
+               dev_drv->ops->extern_func(dev_drv, UNMASK_PAGE_FAULT);
+               page_fault = dev_drv->ops->extern_func(dev_drv, GET_PAGE_FAULT);
+       }
+       if (page_fault) {
+               pr_info("last config:\n");
+               for(i = 0; i < dev_drv->lcdc_win_num; i++) {
+                       for(j = 0; j < RK_WIN_MAX_AREA; j++) {
+                               if ((j > 0) && (dev_drv->area_support[i] == 1))
+                                       continue;
+                               pr_info("win[%d]area[%d],state=%d,addr=0x%08x\n",
+                                       i, j, g_last_state[i][j], g_last_addr[i][j]);
+                       }
+               }
+
+               pr_info("last freed buffer:\n");
+               for (i = 0; (freed_addr[i] != 0xfefefefe) && freed_addr[i]; i++)
+                       pr_info("%d:0x%08x\n", i, freed_addr[i]);
+
+               dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
+               pr_info("vop now state:\n");
+               for(i = 0; i < dev_drv->lcdc_win_num; i++) {
+                       for(j = 0; j < RK_WIN_MAX_AREA; j++) {
+                               if ((j > 0) && (dev_drv->area_support[i] == 1))
+                                       continue;
+                               state = dev_drv->ops->get_win_state(dev_drv, i, j);
+                               pr_info("win[%d]area[%d],state=%d,addr=0x%08x\n",
+                                       i, j, state, dsp_addr[i][j]);
+                   }
+               }
+               pr_info("now config:\n");
+               for(i = 0; i < dev_drv->lcdc_win_num; i++) {
+                       for(j = 0; j < RK_WIN_MAX_AREA; j++) {
+                               if ((j > 0) && (dev_drv->area_support[i] == 1))
+                                       continue;
+                               pr_info("win[%d]area[%d],state=%d,addr=0x%08x\n",
+                                       i, j, g_now_config_state[i][j],
+                                       g_now_config_addr[i][j]);
+                       }
+               }
+               for (i = 0; i < DUMP_FRAME_NUM; i++)
+                       rk_fb_config_debug(dev_drv, &(dev_drv->tmp_win_cfg[i]),
+                                          &(dev_drv->tmp_regs[i]), 0);
+       }
+
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               for (j = 0; j < RK_WIN_MAX_AREA; j++) {
+                       if ((j > 0) && (dev_drv->area_support[i] == 1))
+                               continue;
+                       g_last_addr[i][j] = g_now_config_addr[i][j];
+                       g_last_state[i][j] = g_now_config_state[i][j];
+               }
+       }
+
+       return page_fault;
+}
 static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
                             struct rk_fb_reg_data *regs)
 {
        int i, j;
        struct rk_lcdc_win *win;
        ktime_t timestamp = dev_drv->vsync_info.timestamp;
-       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        struct rk_fb_reg_win_data *win_data;
        bool wait_for_vsync;
        int count = 100;
-       unsigned int dsp_addr[4];
        long timeout;
-       int win_status = 0;
-
+       int pagefault = 0;
        /* acq_fence wait */
        for (i = 0; i < regs->win_num; i++) {
                win_data = &regs->reg_win_data[i];
@@ -1681,76 +1815,51 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
                win = dev_drv->win[i];
                win_data = rk_fb_get_win_data(regs, i);
                if (win_data) {
-                       if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
-                           (win_data->reg_area_data[0].data_format == YUV420 ||
-                            win_data->reg_area_data[0].data_format == YUV420_NV21 ||
-                            win_data->reg_area_data[0].data_format == YUV420_A))
-                               continue;
                        mutex_lock(&dev_drv->win_config);
                        rk_fb_update_win(dev_drv, win, win_data);
                        win->state = 1;
                        dev_drv->ops->set_par(dev_drv, i);
                        dev_drv->ops->pan_display(dev_drv, i);
                        mutex_unlock(&dev_drv->win_config);
+               } else {
+                       win->z_order = -1;
+                       win->state = 0;
+                       for (j = 0; j < 4; j++)
+                               win->area[j].state = 0;
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                        if (dev_drv->iommu_enabled) {
-                               g_last_addr[i] = win_data->reg_area_data[0].smem_start +
-                                       win_data->reg_area_data[0].y_offset;
+                               for (j = 0; j < 4; j++) {
+                                       g_now_config_addr[i][j] = 0;
+                                       g_now_config_state[i][j] = 0;
+                               }
                        }
 #endif
-               } else {
-                       win->z_order = -1;
-                       win->state = 0;
                }
        }
        dev_drv->ops->ovl_mgr(dev_drv, 0, 1);
-       dev_drv->ops->cfg_done(dev_drv);
+
+       if (rk_fb_iommu_debug > 0) {
+               pagefault = rk_fb_iommu_page_fault_dump(dev_drv);
+       }
+
+        if (pagefault == 0) {
+               dev_drv->ops->cfg_done(dev_drv);
+       } else {
+                sw_sync_timeline_inc(dev_drv->timeline, 1);
+       }
 
        do {
                timestamp = dev_drv->vsync_info.timestamp;
                timeout = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
                                ktime_compare(dev_drv->vsync_info.timestamp, timestamp) > 0,
-                               msecs_to_jiffies(25));
-
-               dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
-               wait_for_vsync = false;
-               for (i = 0; i < dev_drv->lcdc_win_num; i++) {
-                        if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
-                           (!strcmp(dev_drv->win[i]->name, "hwc")))
-                               continue;
-                       if (dev_drv->win[i]->state == 1) {
-                               u32 new_start =
-                                   dev_drv->win[i]->area[0].smem_start +
-                                   dev_drv->win[i]->area[0].y_offset;
-                               u32 reg_start = dsp_addr[i];
+                               msecs_to_jiffies(50));
 
-                               if ((rk_fb->disp_policy ==
-                                    DISPLAY_POLICY_BOX) &&
-                                   (dev_drv->suspend_flag))
-                                       continue;
-                               if (unlikely(new_start != reg_start)) {
-                                       wait_for_vsync = true;
-                                       dev_info(dev_drv->dev,
-                                              "win%d:new_addr:0x%08x cur_addr:0x%08x--%d\n",
-                                              i, new_start, reg_start, 101 - count);
-                                       break;
-                               }
-                       } else if (dev_drv->win[i]->state == 0) {
-                                if (dev_drv->ops->get_win_state) {
-                                        win_status =
-                                        dev_drv->ops->get_win_state(dev_drv, i);
-                                        if (win_status)
-                                               wait_for_vsync = true;
-                                }
-                       } else {
-                                pr_err("!!!win[%d]state:%d,error!!!\n",
-                                        i, dev_drv->win[i]->state);
-                       }
-               }
+               wait_for_vsync = rk_fb_reg_effect(dev_drv, regs, count);
        } while (wait_for_vsync && count--);
 #ifdef H_USE_FENCE
        sw_sync_timeline_inc(dev_drv->timeline, 1);
 #endif
+
        if (dev_drv->front_regs) {
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
@@ -1782,6 +1891,8 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
        dev_drv->front_regs = regs;
 
        mutex_unlock(&dev_drv->front_lock);
+
+       trace_buffer_dump(&fb_pdev->dev, dev_drv);
 }
 
 static void rk_fb_update_regs_handler(struct kthread_work *work)
@@ -1807,6 +1918,9 @@ static void rk_fb_update_regs_handler(struct kthread_work *work)
 static int rk_fb_check_config_var(struct rk_fb_area_par *area_par,
                                  struct rk_screen *screen)
 {
+       if (area_par->phy_addr > 0)
+               pr_err("%s[%d], phy_addr = 0x%x\n",
+                      __func__, __LINE__, area_par->phy_addr);
        if ((area_par->x_offset + area_par->xact > area_par->xvir) ||
            (area_par->xact <= 0) || (area_par->yact <= 0) ||
            (area_par->xvir <= 0) || (area_par->yvir <= 0)) {
@@ -1829,6 +1943,100 @@ static int rk_fb_check_config_var(struct rk_fb_area_par *area_par,
        return 0;
 }
 
+static int rk_fb_config_debug(struct rk_lcdc_driver *dev_drv,
+                             struct rk_fb_win_cfg_data *win_data,
+                             struct rk_fb_reg_data *regs, u32 cmd)
+{
+       int i, j;
+       struct rk_fb_win_par *win_par;
+       struct rk_fb_area_par *area_par;
+       struct rk_fb_reg_win_data *reg_win_data;
+       struct rk_fb_reg_area_data *area_data;
+
+       fb_dbg(cmd, "-------------frame start-------------\n");
+       fb_dbg(cmd, "user config:\n");
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               win_par = &(win_data->win_par[i]);
+               if ((win_par->area_par[0].ion_fd <= 0) &&
+                   (win_par->area_par[0].phy_addr <= 0))
+                       continue;
+               fb_dbg(cmd, "win[%d]:z_order=%d,galhpa_v=%d\n",
+                      win_par->win_id, win_par->z_order,
+                      win_par->g_alpha_val);
+               for (j = 0; j < RK_WIN_MAX_AREA; j++) {
+                       area_par = &(win_par->area_par[j]);
+                       if (((j > 0) && (dev_drv->area_support[i] == 1)) ||
+                           ((win_par->area_par[j].ion_fd <= 0) &&
+                            (win_par->area_par[j].phy_addr <= 0)))
+                               continue;
+                       fb_dbg(cmd, " area[%d]:fmt=%d,ion_fd=%d,phy_add=0x%x,xoff=%d,yoff=%d\n",
+                              j, area_par->data_format, area_par->ion_fd,
+                              area_par->phy_addr, area_par->x_offset,
+                              area_par->y_offset);
+                       fb_dbg(cmd, "      xpos=%d,ypos=%d,xsize=%d,ysize=%d\n",
+                              area_par->xpos, area_par->ypos,
+                              area_par->xsize, area_par->ysize);
+                       fb_dbg(cmd, "      xact=%d,yact=%d,xvir=%d,yvir=%d\n",
+                              area_par->xact, area_par->yact,
+                              area_par->xvir, area_par->yvir);
+               }
+       }
+
+       fb_dbg(cmd, "regs data:\n");
+       fb_dbg(cmd, "win_num=%d,buf_num=%d\n",
+              regs->win_num, regs->buf_num);
+       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               reg_win_data = &(regs->reg_win_data[i]);
+               if (reg_win_data->reg_area_data[0].smem_start <= 0)
+                       continue;
+               fb_dbg(cmd, "win[%d]:z_order=%d,area_num=%d,area_buf_num=%d\n",
+                      reg_win_data->win_id, reg_win_data->z_order,
+                      reg_win_data->area_num, reg_win_data->area_buf_num);
+               for (j = 0; j < RK_WIN_MAX_AREA; j++) {
+                       area_data = &(reg_win_data->reg_area_data[j]);
+                       if (((j > 0) && (dev_drv->area_support[i] == 1)) ||
+                           (area_data->smem_start <= 0))
+                               continue;
+                       fb_dbg(cmd, " area[%d]:fmt=%d,ion=%p,smem_star=0x%lx,cbr_star=0x%lx\n",
+                              j, area_data->data_format, area_data->ion_handle,
+                              area_data->smem_start, area_data->cbr_start);
+                       fb_dbg(cmd, "      yoff=0x%x,coff=0x%x,area_data->buff_len=%x\n",
+                              area_data->y_offset, area_data->c_offset,area_data->buff_len);
+                       fb_dbg(cmd, "      xpos=%d,ypos=%d,xsize=%d,ysize=%d\n",
+                              area_data->xpos, area_data->ypos,
+                              area_data->xsize, area_data->ysize);
+                       fb_dbg(cmd, "      xact=%d,yact=%d,xvir=%d,yvir=%d\n",
+                              area_data->xact, area_data->yact,
+                              area_data->xvir, area_data->yvir);
+               }
+       }
+       fb_dbg(cmd, "-------------frame end---------------\n");
+
+       return 0;
+}
+static int rk_fb_config_backup(struct rk_lcdc_driver *dev_drv,
+                                  struct rk_fb_win_cfg_data *win_cfg,
+                                  struct rk_fb_reg_data *regs)
+{
+       int i;
+
+       /*2->1->0: 0 is newest*/
+       for (i = 0; i < DUMP_FRAME_NUM - 1; i++) {
+               memcpy(&(dev_drv->tmp_win_cfg[DUMP_FRAME_NUM-1-i]),
+                      &(dev_drv->tmp_win_cfg[DUMP_FRAME_NUM-2-i]),
+                      sizeof(struct rk_fb_win_cfg_data));
+               memcpy(&(dev_drv->tmp_regs[DUMP_FRAME_NUM-1-i]),
+                      &(dev_drv->tmp_regs[DUMP_FRAME_NUM-2-i]),
+                      sizeof(struct rk_fb_reg_data));
+       }
+
+       memcpy(&(dev_drv->tmp_win_cfg[0]), win_cfg,
+              sizeof(struct rk_fb_win_cfg_data));
+       memcpy(&(dev_drv->tmp_regs[0]), regs,
+              sizeof(struct rk_fb_reg_data));
+
+       return 0;
+}
 static int rk_fb_set_win_buffer(struct fb_info *info,
                                struct rk_fb_win_par *win_par,
                                struct rk_fb_reg_win_data *reg_win_data)
@@ -1863,7 +2071,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
 
        reg_win_data->reg_area_data[0].smem_start = -1;
        reg_win_data->area_num = 0;
-       fbi = rk_fb->fb[reg_win_data->win_id];
+       fbi = rk_fb->fb[win_par->win_id + dev_drv->fb_index_base];
        if (win_par->area_par[0].phy_addr == 0) {
                for (i = 0; i < RK_WIN_MAX_AREA; i++) {
                        ion_fd = win_par->area_par[i].ion_fd;
@@ -1874,10 +2082,9 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                                if (IS_ERR(hdl)) {
                                        pr_info("%s: Could not import handle:"
                                                " %ld\n", __func__, (long)hdl);
-                                       /*return -EINVAL; */
+                                       return -EINVAL;
                                        break;
                                }
-                               reg_win_data->area_num++;
                                reg_win_data->reg_area_data[i].ion_handle = hdl;
 #ifndef CONFIG_ROCKCHIP_IOMMU
                                ret = ion_phys(rk_fb->ion_client, hdl, &phy_addr,
@@ -1899,6 +2106,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                                        return -ENOMEM;
                                }
                                reg_win_data->reg_area_data[i].smem_start = phy_addr;
+                               reg_win_data->area_num++;
                                reg_win_data->area_buf_num++;
                                reg_win_data->reg_area_data[i].index_buf = 1;
                                reg_win_data->reg_area_data[i].buff_len = len;
@@ -1912,8 +2120,13 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                fbi->screen_base = phys_to_virt(win_par->area_par[0].phy_addr);
        }
 
-       if (reg_win_data->area_num == 0)
+       if (reg_win_data->area_num == 0) {
+               for (i = 0; i < RK_WIN_MAX_AREA; i++)
+                       reg_win_data->reg_area_data[i].smem_start = 0;
+               reg_win_data->z_order = -1;
+               reg_win_data->win_id = -1;
                return 0;
+       }
 
        for (i = 0; i < reg_win_data->area_num; i++) {
                acq_fence_fd = win_par->area_par[i].acq_fence_fd;
@@ -1933,9 +2146,11 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
 
        reg_win_data->mirror_en = win_par->mirror_en;
        for (i = 0; i < reg_win_data->area_num; i++) {
-               rk_fb_check_config_var(&win_par->area_par[i], screen);
-
-               fb_data_fmt = rk_fb_data_fmt(win_par->area_par[i].data_format, 0);
+               u8 data_format = win_par->area_par[i].data_format;
+               /*rk_fb_check_config_var(&win_par->area_par[i], screen);*/
+               reg_win_data->colorspace = CSC_FORMAT(data_format);
+               data_format &= ~CSC_MASK;
+               fb_data_fmt = rk_fb_data_fmt(data_format, 0);
                reg_win_data->reg_area_data[i].data_format = fb_data_fmt;
                if (fb_data_fmt >= FBDC_RGB_565) {
                        reg_win_data->reg_area_data[i].fbdc_en = 1;
@@ -1950,6 +2165,18 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                             (fb_data_fmt == FBDC_ARGB_888) ||
                             (fb_data_fmt == FBDC_ABGR_888) ||
                             (fb_data_fmt == ABGR888)) ? 1 : 0;
+               /*act_height should be 2 pix align for interlace output*/
+               if (win_par->area_par[i].yact % 2 == 1) {
+                       win_par->area_par[i].yact  -= 1;
+                       win_par->area_par[i].ysize -= 1;
+               }
+
+               /* buf offset should be 2 pix align*/
+               if (win_par->area_par[i].x_offset % 2 == 1) {
+                       win_par->area_par[i].x_offset += 1;
+                       win_par->area_par[i].xact -= 1;
+               }
+
                /* visiable pos in panel */
                reg_win_data->reg_area_data[i].xpos = win_par->area_par[i].xpos;
                reg_win_data->reg_area_data[i].ypos = win_par->area_par[i].ypos;
@@ -2011,7 +2238,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                if ((fb_data_fmt != YUV420) &&
                    (fb_data_fmt != YUV420_NV21) &&
                    (fb_data_fmt != YUV422) &&
-                    (fb_data_fmt != YUV444)) {
+                    (fb_data_fmt != YUV444) &&
+                    dev_drv->iommu_enabled) {
                         buff_len = reg_win_data->reg_area_data[i].y_offset +
                                 reg_win_data->reg_area_data[i].xvir *
                                 reg_win_data->reg_area_data[i].yact *
@@ -2040,8 +2268,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        case YUV422_A:
                is_pic_yuv = 1;
                stride = stride_32bit_1;
-               uv_stride = stride_32bit_1 >> 1;
-               uv_x_off = xoffset >> 1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
                uv_y_off = yoffset;
                fix->line_length = stride;
                uv_y_act = win_par->area_par[0].yact >> 1;
@@ -2105,7 +2333,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                        reg_win_data->reg_area_data[0].smem_start -
                        reg_win_data->reg_area_data[0].xoff*
                        pixel_width / 16 ;
-               if (buff_len > reg_win_data->reg_area_data[0].buff_len)
+               if ((buff_len > reg_win_data->reg_area_data[0].buff_len) &&
+                     dev_drv->iommu_enabled)
                        pr_err("\n!!!!!!error: fmt=%d,xvir[%d]*"
                               "yact[%d]*bpp[%d]"
                               "=buff_len[0x%x]>>mmu len=0x%x\n",
@@ -2118,9 +2347,10 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
 
        /* record buffer information for rk_fb_disp_scale to prevent fence timeout
         * because rk_fb_disp_scale will call function info->fbops->fb_set_par(info);
+        * delete by hjc for new hdmi overscan framework
         */
-       info->var.yoffset = yoffset;
-       info->var.xoffset = xoffset;
+       /*info->var.yoffset = yoffset;
+       info->var.xoffset = xoffset;*/
        return 0;
 }
 
@@ -2139,32 +2369,49 @@ static int rk_fb_set_win_config(struct fb_info *info,
 #endif
        int ret = 0, i, j = 0;
        int list_is_empty = 0;
+        struct rk_screen *screen = dev_drv->cur_screen;
+
+       mutex_lock(&dev_drv->output_lock);
 
-       if (dev_drv->suspend_flag) {
+        for (i = 0; i < 4; i++) {
+                for (j = 0; j < 4; j++) {
+                        if ((win_data->win_par[i].area_par[j].ion_fd > 0) ||
+                            (win_data->win_par[i].area_par[j].phy_addr > 0))
+                                ret += rk_fb_check_config_var(
+                                        &win_data->win_par[i].area_par[j],
+                                        screen);
+                }
+        }
+       if ((dev_drv->suspend_flag) || (dev_drv->hdmi_switch) || (ret < 0)) {
                dev_drv->timeline_max++;
                sw_sync_timeline_inc(dev_drv->timeline, 1);
-               return 0;
+               if (dev_drv->suspend_flag)
+                       pr_err("suspend_flag=%d\n", dev_drv->suspend_flag);
+               else if (dev_drv->hdmi_switch)
+                       pr_err("hdmi switch = %d\n", dev_drv->hdmi_switch);
+               else
+                       pr_err("error config ,ignore\n");
+               for (j = 0; j < RK_MAX_BUF_NUM; j++)
+                       win_data->rel_fence_fd[j] = -1;
+               win_data->ret_fence_fd = -1;
+               goto err;
        }
 
        regs = kzalloc(sizeof(struct rk_fb_reg_data), GFP_KERNEL);
        if (!regs) {
                printk(KERN_INFO "could not allocate rk_fb_reg_data\n");
                ret = -ENOMEM;
-               return ret;
+               goto err;
        }
 
-/*
-       regs->post_cfg.xpos = win_data->post_cfg.xpos;
-       regs->post_cfg.ypos = win_data->post_cfg.ypos;
-       regs->post_cfg.xsize = win_data->post_cfg.xsize;
-       regs->post_cfg.ysize = win_data->post_cfg.xsize;
-*/
-
-       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+       for (i = 0,j = 0; i < dev_drv->lcdc_win_num; i++) {
                if (win_data->win_par[i].win_id < dev_drv->lcdc_win_num) {
                        if (rk_fb_set_win_buffer(info, &win_data->win_par[i],
-                                                       &regs->reg_win_data[j]))
-                               return -ENOMEM;
+                                                &regs->reg_win_data[j])) {
+                               ret = -ENOMEM;
+                               pr_info("error:%s[%d]\n", __func__,__LINE__);
+                               goto err2;
+                       }
                        if (regs->reg_win_data[j].area_num > 0) {
                                regs->win_num++;
                                regs->buf_num +=
@@ -2178,10 +2425,18 @@ static int rk_fb_set_win_config(struct fb_info *info,
                }
        }
 
-       mutex_lock(&dev_drv->output_lock);
+       if (regs->win_num <= 0)
+               goto err_null_frame;
 
        dev_drv->timeline_max++;
 #ifdef H_USE_FENCE
+       win_data->ret_fence_fd = get_unused_fd();
+       if (win_data->ret_fence_fd < 0) {
+               pr_err("ret_fence_fd=%d\n", win_data->ret_fence_fd);
+               win_data->ret_fence_fd = -1;
+               ret = -EFAULT;
+               goto err2;
+       }
        for (i = 0; i < RK_MAX_BUF_NUM; i++) {
                if (i < regs->buf_num) {
                        sprintf(fence_name, "fence%d", i);
@@ -2190,7 +2445,7 @@ static int rk_fb_set_win_config(struct fb_info *info,
                                printk(KERN_INFO "rel_fence_fd=%d\n",
                                       win_data->rel_fence_fd[i]);
                                ret = -EFAULT;
-                               goto err;
+                               goto err2;
                        }
                        release_sync_pt[i] =
                            sw_sync_pt_create(dev_drv->timeline,
@@ -2204,13 +2459,6 @@ static int rk_fb_set_win_config(struct fb_info *info,
                }
        }
 
-       win_data->ret_fence_fd = get_unused_fd();
-       if (win_data->ret_fence_fd < 0) {
-               printk("ret_fence_fd=%d\n", win_data->ret_fence_fd);
-               win_data->ret_fence_fd = -1;
-               ret = -EFAULT;
-               goto err;
-       }
        retire_sync_pt =
            sw_sync_pt_create(dev_drv->timeline, dev_drv->timeline_max);
        retire_fence = sync_fence_create("ret_fence", retire_sync_pt);
@@ -2244,9 +2492,22 @@ static int rk_fb_set_win_config(struct fb_info *info,
                        rk_fb_update_reg(dev_drv, regs);
                }
        }
-
+       if (rk_fb_debug_lvl > 0)
+               rk_fb_config_debug(dev_drv, win_data, regs, rk_fb_debug_lvl);
+       if (rk_fb_iommu_debug > 0)
+               rk_fb_config_backup(dev_drv, win_data, regs);
 err:
        mutex_unlock(&dev_drv->output_lock);
+       return ret;
+err_null_frame:
+       for (j = 0; j < RK_MAX_BUF_NUM; j++)
+               win_data->rel_fence_fd[j] = -1;
+       win_data->ret_fence_fd = -1;
+       pr_info("win num = %d,null frame\n", regs->win_num);
+err2:
+       kfree(regs);
+       mutex_unlock(&dev_drv->output_lock);
+
        return ret;
 }
 
@@ -2333,9 +2594,9 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
        int enable;     /* enable fb:1 enable;0 disable */
        int ovl;        /* overlay:0 win1 on the top of win0;1,win0 on the top of win1 */
        int num_buf;    /* buffer_number */
-       int ret;
+       int ret = 0;
        struct rk_fb_win_cfg_data win_data;
-       unsigned int dsp_addr[4];
+       unsigned int dsp_addr[4][4];
        int list_stat;
 
        int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
@@ -2458,14 +2719,14 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case RK_FBIOSET_ENABLE:
                if (copy_from_user(&enable, argp, sizeof(enable)))
                        return -EFAULT;
-                               if (enable)
+                               if (enable && fb_par->state)
                                        fb_par->state++;
                                else
                                        fb_par->state--;
                dev_drv->ops->open(dev_drv, win_id, enable);
                break;
        case RK_FBIOGET_ENABLE:
-               enable = dev_drv->ops->get_win_state(dev_drv, win_id);
+               enable = dev_drv->ops->get_win_state(dev_drv, win_id, 0);
                if (copy_to_user(argp, &enable, sizeof(enable)))
                        return -EFAULT;
                break;
@@ -2568,7 +2829,7 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
                };
 
                dev_drv->wait_fs = win_data.wait_fs;
-               rk_fb_set_win_config(info, &win_data);
+               ret = rk_fb_set_win_config(info, &win_data);
 
                if (copy_to_user((struct rk_fb_win_cfg_data __user *)arg,
                                 &win_data, sizeof(win_data))) {
@@ -2576,13 +2837,17 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
                }
                memset(&win_data, 0, sizeof(struct rk_fb_win_cfg_data));
+
+               if (dev_drv->uboot_logo)
+                       dev_drv->uboot_logo = 0;
+
                break;
        default:
                dev_drv->ops->ioctl(dev_drv, cmd, arg, win_id);
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int rk_fb_blank(int blank_mode, struct fb_info *info)
@@ -2598,6 +2863,7 @@ static int rk_fb_blank(int blank_mode, struct fb_info *info)
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fix->id);
        if (win_id < 0)
                return -ENODEV;
+       mutex_lock(&dev_drv->switch_screen);
 #if defined(CONFIG_RK_HDMI)
        if ((rk_fb->disp_mode == ONE_DUAL) &&
            (hdmi_get_hotplug() == HDMI_HPD_ACTIVED)) {
@@ -2607,6 +2873,7 @@ static int rk_fb_blank(int blank_mode, struct fb_info *info)
        {
                dev_drv->ops->blank(dev_drv, win_id, blank_mode);
        }
+       mutex_unlock(&dev_drv->switch_screen);
        return 0;
 }
 
@@ -2785,7 +3052,6 @@ static int rk_fb_set_par(struct fb_info *info)
        struct fb_fix_screeninfo *fix = &info->fix;
        struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par;
        struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv;
-       struct rk_fb *rk_fb = dev_get_drvdata(info->device);
        struct rk_lcdc_win *win = NULL;
        struct rk_screen *screen = dev_drv->cur_screen;
        int win_id = 0;
@@ -2807,6 +3073,8 @@ static int rk_fb_set_par(struct fb_info *info)
        u16 uv_x_off, uv_y_off, uv_y_act;
        u8 is_pic_yuv = 0;
        /*var->pixclock = dev_drv->pixclock;*/
+       if (dev_drv->suspend_flag)
+               return 0;
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
        if (win_id < 0)
                return -ENODEV;
@@ -2826,6 +3094,8 @@ static int rk_fb_set_par(struct fb_info *info)
                ysize = screen->mode.yres;
        }
 
+       win->colorspace = CSC_FORMAT(data_format);
+       data_format &= ~CSC_MASK;
        fb_data_fmt = rk_fb_data_fmt(data_format, var->bits_per_pixel);
        if (fb_data_fmt >= FBDC_RGB_565) {
                win->area[0].fbdc_en = 1;
@@ -2845,8 +3115,8 @@ static int rk_fb_set_par(struct fb_info *info)
        case YUV422_A:
                is_pic_yuv = 1;
                stride = stride_32bit_1;
-               uv_stride = stride_32bit_1 >> 1;
-               uv_x_off = xoffset >> 1;
+               uv_stride = stride_32bit_1;
+               uv_x_off = xoffset;
                uv_y_off = yoffset;
                fix->line_length = stride;
                cblen = crlen = (xvir * yvir) >> 1;
@@ -2903,12 +3173,6 @@ static int rk_fb_set_par(struct fb_info *info)
                         (win->area[0].format == ABGR888)) ? 1 : 0;
        win->g_alpha_val = 0;
 
-       if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
-           (win->area[0].format == YUV420 ||
-            win->area[0].format == YUV420_NV21 ||
-            win->area[0].format == YUV420_A))
-                win->state = 1;
-
        dev_drv->ops->set_par(dev_drv, win_id);
 
        return 0;
@@ -3022,7 +3286,7 @@ static int rk_fb_wait_for_vsync_thread(void *data)
 {
        struct rk_lcdc_driver *dev_drv = data;
        struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
-       struct fb_info *fbi = rk_fb->fb[0];
+       struct fb_info *fbi = rk_fb->fb[dev_drv->fb_index_base];
 
        while (!kthread_should_stop()) {
                ktime_t timestamp = dev_drv->vsync_info.timestamp;
@@ -3113,19 +3377,21 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        struct fb_info *info = NULL;
        struct rk_fb_par *fb_par = NULL;
        struct rk_lcdc_driver *dev_drv = NULL;
+       struct rk_lcdc_win *win;
        char name[6] = {0};
-       int i, win_id, load_screen = 0;
+       int i, win_id;
+       static bool load_screen = false;
+       char *envp[4];
+       char envplcdc[32];
+       char envpfbdev[32];
+       int ret, list_is_empty = 0;
 
        if (unlikely(!rk_fb) || unlikely(!screen))
                return -ENODEV;
 
-       hdmi_switch_complete = 0;
        /* get lcdc driver */
        sprintf(name, "lcdc%d", lcdc_id);
-       if (rk_fb->disp_mode != DUAL)
-               dev_drv = rk_fb->lcdc_dev_drv[0];
-       else
-               dev_drv = rk_get_lcdc_drv(name);
+       dev_drv = rk_get_lcdc_drv(name);
 
        if (dev_drv == NULL) {
                printk(KERN_ERR "%s driver not found!", name);
@@ -3140,32 +3406,68 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                dev_drv->id);
        if (enable == 2 /*&& dev_drv->enable*/)
                return 0;
+       pr_info("switch:en=%d,lcdc_id=%d,screen type=%d,cur type=%d\n",
+               enable, lcdc_id, screen->type, dev_drv->cur_screen->type);
+
+       mutex_lock(&dev_drv->switch_screen);
+       hdmi_switch_state = 0;
+       dev_drv->hdmi_switch = 1;
+       if (!dev_drv->uboot_logo) {
+               mdelay(200);
+               list_is_empty = list_empty(&dev_drv->update_regs_list) &&
+                                          list_empty(&dev_drv->saved_list);
+               if (!list_is_empty) {
+                       ret = wait_event_timeout(dev_drv->update_regs_wait,
+                                                list_empty(&dev_drv->update_regs_list) &&
+                                                list_empty(&dev_drv->saved_list),
+                                                msecs_to_jiffies(60));
+                       if (ret <= 0)
+                               pr_info("%s: wait update_regs_wait timeout\n",
+                                       __func__);
+               }
+       }
+
+       envp[0] = "switch screen";
+       memset(envplcdc, 0, sizeof(envplcdc));
+       memset(envpfbdev, 0, sizeof(envpfbdev));
+       sprintf(envplcdc, "SCREEN=%d,ENABLE=%d", screen->type, enable);
+       sprintf(envpfbdev, "FBDEV=%d", dev_drv->fb_index_base);
+       envp[1] = envplcdc;
+       envp[2] = envpfbdev;
+       envp[3] = NULL;
 
        if ((rk_fb->disp_mode == ONE_DUAL) ||
            (rk_fb->disp_mode == NO_DUAL)) {
                if ((dev_drv->ops->backlight_close) &&
-                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP))
                        dev_drv->ops->backlight_close(dev_drv, 1);
-               if (dev_drv->ops->dsp_black)
-                       dev_drv->ops->dsp_black(dev_drv, 1);
+               if (!dev_drv->uboot_logo || load_screen ||
+                               ((rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                                (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP))) {
+                       if (dev_drv->ops->dsp_black)
+                               dev_drv->ops->dsp_black(dev_drv, 0);
+               }
                if ((dev_drv->ops->set_screen_scaler) &&
                    (rk_fb->disp_mode == ONE_DUAL))
                        dev_drv->ops->set_screen_scaler(dev_drv,
                                                        dev_drv->screen0, 0);
        }
-       if (dev_drv->uboot_logo && (screen->type != dev_drv->cur_screen->type))
-               dev_drv->uboot_logo = 0;
        if (!enable) {
                /* if screen type is different, we do not disable lcdc. */
-               if (dev_drv->cur_screen->type != screen->type)
+               if (dev_drv->cur_screen->type != screen->type) {
+                       dev_drv->hdmi_switch = 0;
+                       mutex_unlock(&dev_drv->switch_screen);
                        return 0;
+               }
 
                /* if used one lcdc to dual disp, no need to close win */
                if ((rk_fb->disp_mode == ONE_DUAL) ||
-                   (rk_fb->disp_mode == NO_DUAL)) {
+                   ((rk_fb->disp_mode == NO_DUAL) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP))) {
                        dev_drv->cur_screen = dev_drv->screen0;
                        dev_drv->ops->load_screen(dev_drv, 1);
-
                        /* force modify dsp size */
                        info = rk_fb->fb[dev_drv->fb_index_base];
                        info->var.grayscale &= 0xff;
@@ -3173,14 +3475,29 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                (dev_drv->cur_screen->mode.xres << 8) +
                                (dev_drv->cur_screen->mode.yres << 20);
                        mutex_lock(&dev_drv->win_config);
+                       info->var.xoffset = 0;
+                       info->var.yoffset = 0;
                        info->fbops->fb_set_par(info);
                        info->fbops->fb_pan_display(&info->var, info);
                        mutex_unlock(&dev_drv->win_config);
 
-                       if (dev_drv->ops->dsp_black)
-                               dev_drv->ops->dsp_black(dev_drv, 0);
+                       /*
+                        * if currently is loader display, black until new
+                        * display job.
+                        */
+                       if (dev_drv->uboot_logo) {
+                               for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+                                       if (dev_drv->win[i] && dev_drv->win[i]->state &&
+                                           dev_drv->ops->win_direct_en)
+                                               dev_drv->ops->win_direct_en(dev_drv, i, 0);
+                               }
+                       }
+
+                       /*if (dev_drv->ops->dsp_black)
+                               dev_drv->ops->dsp_black(dev_drv, 0);*/
                        if ((dev_drv->ops->backlight_close) &&
-                           (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
+                           (rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                           (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP))
                                dev_drv->ops->backlight_close(dev_drv, 0);
                } else if (rk_fb->num_lcdc > 1) {
                        /* If there is more than one lcdc device, we disable
@@ -3192,10 +3509,20 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                        dev_drv->ops->open(dev_drv, i, 0);
                        }
                }
+                kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
 
-               hdmi_switch_complete = 0;
+               hdmi_switch_state = 0;
+               dev_drv->hdmi_switch = 0;
+               mutex_unlock(&dev_drv->switch_screen);
                return 0;
        } else {
+               if (dev_drv->uboot_logo) {
+                       if (dev_drv->cur_screen->mode.xres !=
+                               screen->mode.xres ||
+                           dev_drv->cur_screen->mode.yres !=
+                               screen->mode.yres)
+                               load_screen = 1;
+               }
                if (dev_drv->screen1)
                        dev_drv->cur_screen = dev_drv->screen1;
 
@@ -3205,52 +3532,74 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR;
                dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR;
        }
-       if ((!dev_drv->uboot_logo) ||
-           (rk_fb->disp_policy != DISPLAY_POLICY_BOX)) {
+       if (!dev_drv->uboot_logo || load_screen ||
+           ((rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+            (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP))) {
                for (i = 0; i < dev_drv->lcdc_win_num; i++) {
                        info = rk_fb->fb[dev_drv->fb_index_base + i];
                        fb_par = (struct rk_fb_par *)info->par;
                        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
-                       if (dev_drv->win[win_id]) {
-                               if (fb_par->state) {
-                                       if (!dev_drv->win[win_id]->state) {
-                                               dev_drv->ops->open(dev_drv, win_id, 1);
-                                               dev_drv->suspend_flag = 0;
-                                       }
-                                       if (!load_screen) {
-                                               dev_drv->ops->load_screen(dev_drv, 1);
-                                               load_screen = 1;
-                                       }
-                                       info->var.activate |= FB_ACTIVATE_FORCE;
-                                       if (rk_fb->disp_mode == ONE_DUAL) {
-                                               info->var.grayscale &= 0xff;
-                                               info->var.grayscale |=
-                                                       (dev_drv->cur_screen->xsize << 8) +
-                                                       (dev_drv->cur_screen->ysize << 20);
+                       win = dev_drv->win[win_id];
+                       if (win && fb_par->state) {
+                               mutex_lock(&dev_drv->win_config);
+                               dev_drv->ops->load_screen(dev_drv, 1);
+                               mutex_unlock(&dev_drv->win_config);
+
+                               info->var.activate |= FB_ACTIVATE_FORCE;
+                               if (rk_fb->disp_mode == ONE_DUAL) {
+                                       info->var.grayscale &= 0xff;
+                                       info->var.grayscale |=
+                                               (dev_drv->cur_screen->xsize << 8) +
+                                               (dev_drv->cur_screen->ysize << 20);
+                               }
+                               if (dev_drv->uboot_logo && win->state) {
+                                       if (win->area[0].xpos ||
+                                           win->area[0].ypos) {
+                                               win->area[0].xpos =
+                                                       (screen->mode.xres -
+                                                        win->area[0].xsize)/2;
+                                               win->area[0].ypos =
+                                                       (screen->mode.yres -
+                                                        win->area[0].ysize)/2;
+                                       } else {
+                                               win->area[0].xsize = screen->mode.xres;
+                                               win->area[0].ysize = screen->mode.yres;
                                        }
-
+                                       dev_drv->ops->set_par(dev_drv, i);
+                                       dev_drv->ops->cfg_done(dev_drv);
+                               } else if (!dev_drv->win[win_id]->state) {
+                                       dev_drv->ops->open(dev_drv, win_id, 1);
+                                       dev_drv->suspend_flag = 0;
                                        mutex_lock(&dev_drv->win_config);
+                                       info->var.xoffset = 0;
+                                       info->var.yoffset = 0;
                                        info->fbops->fb_set_par(info);
                                        info->fbops->fb_pan_display(&info->var, info);
                                        mutex_unlock(&dev_drv->win_config);
                                }
                        }
                }
-       }else {
-               dev_drv->uboot_logo = 0;
+       } else {
+               dev_drv->ops->load_screen(dev_drv, 0);
        }
-       hdmi_switch_complete = 1;
+       kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
+
+       hdmi_switch_state = 1;
+       load_screen = true;
+       dev_drv->hdmi_switch = 0;
        if ((rk_fb->disp_mode == ONE_DUAL) || (rk_fb->disp_mode == NO_DUAL)) {
                if ((dev_drv->ops->set_screen_scaler) &&
                    (rk_fb->disp_mode == ONE_DUAL))
                        dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 1);
-               if (dev_drv->ops->dsp_black)
-                       dev_drv->ops->dsp_black(dev_drv, 0);
+               /*if (dev_drv->ops->dsp_black)
+                       dev_drv->ops->dsp_black(dev_drv, 0);*/
                if ((dev_drv->ops->backlight_close) &&
                    (rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX_TEMP) &&
                    (rk_fb->disp_mode == ONE_DUAL))
                        dev_drv->ops->backlight_close(dev_drv, 0);
        }
+       mutex_unlock(&dev_drv->switch_screen);
        return 0;
 }
 
@@ -3276,7 +3625,9 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id)
        if (primary_screen.type == SCREEN_HDMI) {
                return 0;
        }
+       pr_err("fuck not be hear--%s\n",__func__);
 
+       return 0;
        sprintf(name, "lcdc%d", lcdc_id);
 
        if (inf->disp_mode == DUAL) {
@@ -3402,6 +3753,8 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
        dma_addr_t fb_mem_phys;
        void *fb_mem_virt;
 #endif
+       ion_phys_addr_t phy_addr;
+       size_t len;
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
        if (win_id < 0)
@@ -3410,7 +3763,7 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
                win = dev_drv->win[win_id];
 
        if (!strcmp(fbi->fix.id, "fb0")) {
-               fb_mem_size = get_fb_size();
+               fb_mem_size = get_fb_size(dev_drv->reserved_fb);
 #if defined(CONFIG_ION_ROCKCHIP)
                if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0)
                        return -ENOMEM;
@@ -3428,9 +3781,64 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
 #endif
                memset(fbi->screen_base, 0, fbi->fix.smem_len);
        } else {
-               fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
-               fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len;
-               fbi->screen_base = rk_fb->fb[0]->screen_base;
+               if (dev_drv->prop == EXTEND && dev_drv->iommu_enabled) {
+                       struct rk_lcdc_driver *dev_drv_prmry;
+                       int win_id_prmry;
+                       fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+#if defined(CONFIG_ION_ROCKCHIP)
+                       dev_drv_prmry = rk_get_prmry_lcdc_drv();
+                       if (dev_drv_prmry == NULL)
+                               return -ENODEV;
+                       win_id_prmry =
+                               dev_drv_prmry->ops->fb_get_win_id(dev_drv_prmry,
+                                                                fbi->fix.id);
+                       if (win_id_prmry < 0)
+                               return -ENODEV;
+                       else
+                               fb_par->ion_hdl =
+                               dev_drv_prmry->win[win_id_prmry]->area[0].ion_hdl;
+                               fbi->screen_base =
+                                       ion_map_kernel(rk_fb->ion_client,
+                                                      fb_par->ion_hdl);
+                               dev_drv->win[win_id]->area[0].ion_hdl =
+                                       fb_par->ion_hdl;
+       #ifdef CONFIG_ROCKCHIP_IOMMU
+                               if (dev_drv->mmu_dev)
+                                       ret = ion_map_iommu(dev_drv->dev,
+                                                           rk_fb->ion_client,
+                                                           fb_par->ion_hdl,
+                                                           (unsigned long *)&phy_addr,
+                                                           (unsigned long *)&len);
+                               else
+                                       ret = ion_phys(rk_fb->ion_client,
+                                                      fb_par->ion_hdl,
+                                                      &phy_addr, &len);
+       #endif
+                               if (ret < 0) {
+                                       dev_err(fbi->dev, "ion map to get phy addr failed\n");
+                                       return -ENOMEM;
+                               }
+                               fbi->fix.smem_start = phy_addr;
+                               fbi->fix.smem_len = len;
+#else
+                       fb_mem_virt = dma_alloc_writecombine(fbi->dev,
+                                                            fb_mem_size,
+                                                            &fb_mem_phys,
+                                                            GFP_KERNEL);
+                       if (!fb_mem_virt) {
+                               pr_err("%s: Failed to allocate framebuffer\n",
+                                      __func__);
+                               return -ENOMEM;
+                       }
+                       fbi->fix.smem_len = fb_mem_size;
+                       fbi->fix.smem_start = fb_mem_phys;
+                       fbi->screen_base = fb_mem_virt;
+#endif
+               } else {
+                       fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
+                       fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len;
+                       fbi->screen_base = rk_fb->fb[0]->screen_base;
+               }
        }
 
        fbi->screen_size = fbi->fix.smem_len;
@@ -3486,6 +3894,7 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        struct rk_screen *screen = devm_kzalloc(dev_drv->dev,
                                                sizeof(struct rk_screen),
                                                GFP_KERNEL);
+       int i = 0;
 
        if (!screen) {
                dev_err(dev_drv->dev, "malloc screen for lcdc%d fail!",
@@ -3527,16 +3936,19 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        mutex_init(&dev_drv->fb_win_id_mutex);
        mutex_init(&dev_drv->win_config);
        mutex_init(&dev_drv->front_lock);
+       mutex_init(&dev_drv->switch_screen);
        dev_drv->ops->fb_win_remap(dev_drv, dev_drv->fb_win_map);
        dev_drv->first_frame = 1;
        dev_drv->overscan.left = 100;
        dev_drv->overscan.top = 100;
        dev_drv->overscan.right = 100;
        dev_drv->overscan.bottom = 100;
+       for (i = 0; i < RK30_MAX_LAYER_SUPPORT; i++)
+               dev_drv->area_support[i] = 1;
+       if (dev_drv->ops->area_support_num)
+               dev_drv->ops->area_support_num(dev_drv, dev_drv->area_support);
        rk_disp_pwr_ctr_parse_dt(dev_drv);
        if (dev_drv->prop == PRMRY) {
-               if (dev_drv->ops->set_dsp_cabc)
-                       dev_drv->ops->set_dsp_cabc(dev_drv, dev_drv->cabc_mode);
                rk_fb_set_prmry_screen(screen);
                rk_fb_get_prmry_screen(screen);
        }
@@ -3595,6 +4007,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
        struct fb_info *fbi;
        struct rk_fb_par *fb_par = NULL;
        int i = 0, ret = 0, index = 0;
+       unsigned long flags;
 
        if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT)
                return -ENXIO;
@@ -3766,7 +4179,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                        xact, yact, width, height);
                                return 0;
                        }
-
+                       local_irq_save(flags);
+                       if (dev_drv->ops->wait_frame_start)
+                               dev_drv->ops->wait_frame_start(dev_drv, 0);
                        if (dev_drv->ops->post_dspbuf) {
                                dev_drv->ops->post_dspbuf(dev_drv,
                                        main_fbi->fix.smem_start,
@@ -3779,10 +4194,11 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                        dev_drv->ops->mmu_en(dev_drv);
                                freed_index = 0;
                        }
-
+                       local_irq_restore(flags);
                        return 0;
                } else if (dev_drv->uboot_logo && uboot_logo_base) {
-                       phys_addr_t start = uboot_logo_base;
+                       u32 start = uboot_logo_base;
+                       u32 start_base = start;
                        int logo_len, i=0;
                        unsigned int nr_pages;
                        struct page **pages;
@@ -3809,8 +4225,8 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                        vaddr = vmap(pages, nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
                        if (!vaddr) {
-                               pr_err("failed to vmap phy addr %x\n",
-                                       uboot_logo_base);
+                               pr_err("failed to vmap phy addr 0x%x\n",
+                                      start_base);
                                return -1;
                        }
 
@@ -3818,7 +4234,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
 
                        kfree(pages);
                        vunmap(vaddr);
-
+                       local_irq_save(flags);
+                       if (dev_drv->ops->wait_frame_start)
+                               dev_drv->ops->wait_frame_start(dev_drv, 0);
                        dev_drv->ops->post_dspbuf(dev_drv,
                                        main_fbi->fix.smem_start,
                                        format, xact, yact,
@@ -3829,6 +4247,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                        dev_drv->ops->mmu_en(dev_drv);
                                freed_index = 0;
                        }
+                       local_irq_restore(flags);
                        return 0;
                } else {
                        if (dev_drv->iommu_enabled) {
@@ -3855,7 +4274,15 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
        } else {
                 struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
                 extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
-                rk_fb_alloc_buffer(extend_fbi);
+               extend_fbi->fbops->fb_open(extend_fbi, 1);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       if (dev_drv->mmu_dev)
+                               rockchip_iovmm_set_fault_handler(dev_drv->dev,
+                                                                rk_fb_sysmmu_fault_handler);
+               }
+#endif
+               rk_fb_alloc_buffer(extend_fbi);
        }
 #endif
        return 0;
@@ -3956,6 +4383,7 @@ static void rk_fb_shutdown(struct platform_device *pdev)
        for (i = 0; i < rk_fb->num_lcdc; i++) {
                if (!rk_fb->lcdc_dev_drv[i])
                        continue;
+               sw_sync_timeline_inc(rk_fb->lcdc_dev_drv[i]->timeline, 1);
        }
 }