From 4f8e3e98373de1dbadfeaf6a96c8700e9aa96cce Mon Sep 17 00:00:00 2001 From: hjc Date: Tue, 26 May 2015 15:54:49 +0800 Subject: [PATCH] rk fb: fix in interlace mode switch between ntsc and pal lead to pagefault Signed-off-by: hjc --- drivers/video/rockchip/lcdc/rk3368_lcdc.c | 31 +++++++++++++++++++++-- drivers/video/rockchip/rk_fb.c | 25 +++++++++++++++--- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/video/rockchip/lcdc/rk3368_lcdc.c b/drivers/video/rockchip/lcdc/rk3368_lcdc.c index 29857eb7cd47..a63852b4a985 100755 --- a/drivers/video/rockchip/lcdc/rk3368_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3368_lcdc.c @@ -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; diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 20ab70cc9dfc..cba2cb3133a4 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -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); -- 2.34.1