rk fb: fix in interlace mode switch between ntsc and pal lead to pagefault
authorhjc <hjc@rock-chips.com>
Tue, 26 May 2015 07:54:49 +0000 (15:54 +0800)
committerhjc <hjc@rock-chips.com>
Tue, 26 May 2015 09:12:04 +0000 (17:12 +0800)
Signed-off-by: hjc <hjc@rock-chips.com>
drivers/video/rockchip/lcdc/rk3368_lcdc.c
drivers/video/rockchip/rk_fb.c

index 29857eb7cd477cc4907fe82ca5137d8e832b29b7..a63852b4a98599b4a3d63d1fa1a00509a888deb6 100755 (executable)
@@ -1840,7 +1840,9 @@ static int lcdc_reset(struct rk_lcdc_driver *dev_drv, bool initscreen)
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
                lcdc_cfg_done(lcdc_dev);
                mdelay(50);
+               lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN, v_STANDBY_EN(1));
                writel_relaxed(0, lcdc_dev->regs + REG_CFG_DONE);
+               mdelay(50);
 #if 0
                if (dev_drv->iommu_enabled) {
                        if (dev_drv->mmu_dev)
@@ -2105,8 +2107,9 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                dev_drv->trsm_ops->enable();    
                if (screen->init)
                        screen->init();
-       if (!lcdc_dev->standby)
-               lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN, v_STANDBY_EN(0));
+       /*if (!lcdc_dev->standby)
+               lcdc_msk_reg(lcdc_dev, SYS_CTRL,
+                       m_STANDBY_EN, v_STANDBY_EN(0));*/
        return 0;
 }
 
@@ -4018,6 +4021,19 @@ static int rk3368_lcdc_config_done(struct rk_lcdc_driver *dev_drv)
        int i;
        unsigned int mask, val;
        struct rk_lcdc_win *win = NULL;
+       u32 line_scane_num, dsp_vs_st_f1;
+
+       if (lcdc_dev->driver.cur_screen->mode.vmode == FB_VMODE_INTERLACED) {
+               dsp_vs_st_f1 = lcdc_readl(lcdc_dev, DSP_VS_ST_END_F1) >> 16;
+               for (i = 0; i < 1000; i++) {
+                       line_scane_num =
+                               lcdc_readl(lcdc_dev, SCAN_LINE_NUM) & 0x1fff;
+                       if (line_scane_num > dsp_vs_st_f1 + 1)
+                               udelay(50);
+                       else
+                               break;
+               }
+       }
 
        spin_lock(&lcdc_dev->reg_lock);
        lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
@@ -4710,12 +4726,17 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
        u32 cabc_pwm_lut_value;
        int pwm_plus;
        int *cabc_gamma_base = NULL;
+       u32 line_scane_num, dsp_vs_st_f1;
+       struct rk_screen *screen = lcdc_dev->driver.cur_screen;
+
        intr_status = lcdc_readl(lcdc_dev, INTR_STATUS);
 
        if (intr_status & m_FS_INTR_STS) {
                timestamp = ktime_get();
                lcdc_msk_reg(lcdc_dev, INTR_CLEAR, m_FS_INTR_CLR,
                             v_FS_INTR_CLR(1));
+               line_scane_num = lcdc_readl(lcdc_dev, SCAN_LINE_NUM) & 0x1fff;
+               dsp_vs_st_f1 = lcdc_readl(lcdc_dev, DSP_VS_ST_END_F1) >> 16;
                /*if(lcdc_dev->driver.wait_fs){ */
                if (0) {
                        spin_lock(&(lcdc_dev->driver.cpl_lock));
@@ -4727,6 +4748,12 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
 #endif
                lcdc_dev->driver.vsync_info.timestamp = timestamp;
                wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
+               if ((screen->mode.vmode == FB_VMODE_NONINTERLACED) ||
+                   (line_scane_num >= dsp_vs_st_f1)) {
+                       lcdc_dev->driver.vsync_info.timestamp = timestamp;
+                       wake_up_interruptible_all(
+                               &lcdc_dev->driver.vsync_info.wait);
+               }
        } else if (intr_status & m_LINE_FLAG0_INTR_STS) {
                lcdc_dev->driver.frame_time.last_framedone_t =
                        lcdc_dev->driver.frame_time.framedone_t;
index 20ab70cc9dfc0ced437fbbe8311e3777a60385c6..cba2cb3133a424f857427454e7bbd0869dfd80fc 100755 (executable)
@@ -1398,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;
 }
 
@@ -2342,9 +2343,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;
 }
 
@@ -3380,6 +3382,7 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        int i, win_id;
        static bool load_screen = false;
        char *envp[3];
+       int ret, list_is_empty = 0;
 
        if (unlikely(!rk_fb) || unlikely(!screen))
                return -ENODEV;
@@ -3410,8 +3413,20 @@ 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)
+       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);
@@ -3463,6 +3478,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);
@@ -3539,6 +3555,7 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                                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);