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
index 7e300399c2587fcf77c21dba0a6412dfcd408fa5..5a30657a10cec7954b9177df684ba249fec49c1b 100755 (executable)
@@ -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*/
@@ -1291,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;
@@ -1385,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;
 }
 
@@ -1442,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][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;
@@ -1502,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;
@@ -1552,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 =
@@ -1562,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 =
@@ -1633,15 +1648,20 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                                    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_last_addr[win->id][i] = win->area[i].smem_start +
+                               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_last_addr[win->id][i] = -1;
+                               if (dev_drv->iommu_enabled) {
+                                       g_now_config_addr[win->id][i] = 0;
+                                       g_now_config_state[win->id][i] = 0;
+                               }
 #endif
                        }
                }
@@ -1667,25 +1687,16 @@ static int rk_fb_reg_effect(struct rk_lcdc_driver *dev_drv,
                             struct rk_fb_reg_data *regs,
                             int count)
 {
-       struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        int i, j, wait_for_vsync = false;
        unsigned int dsp_addr[5][4];
-       unsigned int area_support[5] = {1, 1, 1, 1, 1};
        int win_status = 0;
 
        if (dev_drv->ops->get_dsp_addr)
                dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
 
-       if (dev_drv->ops->area_support_num)
-               dev_drv->ops->area_support_num(dev_drv, area_support);
-
        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;
-
                for (j = 0;j < RK_WIN_MAX_AREA; j++) {
-                       if ((j > 0) && (area_support[i] == 1)) {
+                       if ((j > 0) && (dev_drv->area_support[i] == 1)) {
                                continue;
                        }
                        if (dev_drv->win[i]->area[j].state == 1) {
@@ -1693,10 +1704,6 @@ static int rk_fb_reg_effect(struct rk_lcdc_driver *dev_drv,
                                        dev_drv->win[i]->area[j].smem_start +
                                        dev_drv->win[i]->area[j].y_offset;
                                u32 reg_start = dsp_addr[i][j];
-                               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,
@@ -1721,18 +1728,78 @@ static int rk_fb_reg_effect(struct rk_lcdc_driver *dev_drv,
        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;
        long timeout;
-
+       int pagefault = 0;
        /* acq_fence wait */
        for (i = 0; i < regs->win_num; i++) {
                win_data = &regs->reg_win_data[i];
@@ -1748,11 +1815,6 @@ 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;
@@ -1762,18 +1824,29 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
                } 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) {
-                               for (j = 0; j < 4; j++)
-                                       g_last_addr[i][j] = -1;
+                               for (j = 0; j < 4; j++) {
+                                       g_now_config_addr[i][j] = 0;
+                                       g_now_config_state[i][j] = 0;
+                               }
                        }
 #endif
                }
        }
        dev_drv->ops->ovl_mgr(dev_drv, 0, 1);
-       if (dev_drv->ops->dsp_black)
-               dev_drv->ops->dsp_black(dev_drv, 0);
-       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;
@@ -1845,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)) {
@@ -1867,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)
@@ -1901,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;
@@ -1912,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,
@@ -1937,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;
@@ -1950,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;
@@ -1971,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++) {
+               u8 data_format = win_par->area_par[i].data_format;
                /*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);
+               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;
@@ -1988,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;
@@ -2079,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;
@@ -2158,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;
 }
 
@@ -2181,19 +2371,12 @@ static int rk_fb_set_win_config(struct fb_info *info,
        int list_is_empty = 0;
         struct rk_screen *screen = dev_drv->cur_screen;
 
-       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;
-               return ret;
-       }
-
        mutex_lock(&dev_drv->output_lock);
 
         for (i = 0; i < 4; i++) {
                 for (j = 0; j < 4; j++) {
-                        if (win_data->win_par[i].area_par[j].ion_fd > 0)
+                        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);
@@ -2226,7 +2409,8 @@ static int rk_fb_set_win_config(struct fb_info *info,
                        if (rk_fb_set_win_buffer(info, &win_data->win_par[i],
                                                 &regs->reg_win_data[j])) {
                                ret = -ENOMEM;
-                               goto err;
+                               pr_info("error:%s[%d]\n", __func__,__LINE__);
+                               goto err2;
                        }
                        if (regs->reg_win_data[j].area_num > 0) {
                                regs->win_num++;
@@ -2246,6 +2430,13 @@ static int rk_fb_set_win_config(struct fb_info *info,
 
        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);
@@ -2254,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,
@@ -2301,18 +2492,23 @@ 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:
-       kfree(regs);
        for (j = 0; j < RK_MAX_BUF_NUM; j++)
                win_data->rel_fence_fd[j] = -1;
        win_data->ret_fence_fd = -1;
-       mutex_unlock(&dev_drv->output_lock);
        pr_info("win num = %d,null frame\n", regs->win_num);
-       return 0;
+err2:
+       kfree(regs);
+       mutex_unlock(&dev_drv->output_lock);
+
+       return ret;
 }
 
 #if 1
@@ -2398,7 +2594,7 @@ 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][4];
        int list_stat;
@@ -2633,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))) {
@@ -2651,7 +2847,7 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int rk_fb_blank(int blank_mode, struct fb_info *info)
@@ -2667,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)) {
@@ -2676,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;
 }
 
@@ -2854,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;
@@ -2897,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;
@@ -2916,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;
@@ -2974,13 +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;
-                win->z_order = 0;
-       }
        dev_drv->ops->set_par(dev_drv, win_id);
 
        return 0;
@@ -3094,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;
@@ -3185,20 +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;
        static bool load_screen = false;
-       char *envp[3];
+       char *envp[4];
+       char envplcdc[32];
+       char envpfbdev[32];
+       int ret, list_is_empty = 0;
 
        if (unlikely(!rk_fb) || unlikely(!screen))
                return -ENODEV;
 
        /* 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);
@@ -3219,16 +3412,29 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        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";
-       envp[1] = kmalloc(32, GFP_KERNEL);
-       if (envp[1] == NULL) {
-               pr_err("switch screen kmalloc envp[1] fail\n");
-               mutex_unlock(&dev_drv->switch_screen);
-               return 0;
-       }
-       sprintf(envp[1], "SCREEN=%d,ENABLE=%d", screen->type, enable);
-       envp[2] = NULL;
+       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)) {
@@ -3236,6 +3442,12 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                    (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->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,
@@ -3263,6 +3475,7 @@ 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);
@@ -3274,8 +3487,9 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                         */
                        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->open(dev_drv, i, 0);
+                                       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);
                                }
                        }
 
@@ -3296,13 +3510,19 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        }
                }
                 kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
-                kfree(envp[1]);
 
                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;
 
@@ -3312,44 +3532,60 @@ 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 || load_screen) {
+       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) {
-                                       dev_drv->ops->load_screen(dev_drv, 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);
-                                       }
-                                       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->open(dev_drv, i, 0);
-                                               }
-                                       } 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.yoffset = 0;
-                                               info->fbops->fb_set_par(info);
-                                               info->fbops->fb_pan_display(&info->var, info);
-                                               mutex_unlock(&dev_drv->win_config);
+                       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->ops->load_screen(dev_drv, 0);
        }
        kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
-        kfree(envp[1]);
 
        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) &&
@@ -3517,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)
@@ -3543,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;
@@ -3601,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!",
@@ -3649,6 +3943,10 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        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) {
                rk_fb_set_prmry_screen(screen);
@@ -3709,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;
@@ -3880,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,
@@ -3893,7 +4194,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->uboot_logo && uboot_logo_base) {
                        u32 start = uboot_logo_base;
@@ -3933,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,
@@ -3944,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) {
@@ -3970,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;