From b56a4aaef10ba761cc2c5f7150b3255bdf583320 Mon Sep 17 00:00:00 2001 From: Geng Xiujun Date: Mon, 28 May 2012 18:48:52 +0800 Subject: [PATCH] Gfx-Display: postpone hdmi encoder restore BZ: 38178 after late resume, both mipi and hdmi are enabled, and lock screen should be displayed. while actually an intermediate picture is showed before showing lock screen. the reason is there is a early_suspend callback for fb device, a thread loop in framework check its status to see whether fb device is ready to draw. its level is 100, but the level of gfx_early_suspend is 150. so in early suspend, the sequence is stop_drawing_early_suspend() --> gfx_early_suspend(), while in late_resume, the sequence is gfx_late_resume() --> start_drawing_late_resume(). so the first flip happens after enable pipe and plane. the solution is: 1. for mipi, before enabling pipe and plane, restore a black framebuffer. 2. for hdmi, postpone enable hdmi plane to let flip happen fist. Change-Id: Ib15e72b24d02de97d4f8928afbcbb9fc24743ebd Signed-off-by: Geng Xiujun Reviewed-on: http://android.intel.com:8080/51373 Reviewed-by: Xu, Randy Tested-by: Tong, BoX Reviewed-by: Ai, Ke Reviewed-by: buildbot Tested-by: buildbot --- drivers/staging/mrst/drv/psb_intel_hdmi.c | 122 +++++++++++++++++++++--------- drivers/staging/mrst/drv/psb_intel_hdmi.h | 4 + drivers/staging/mrst/drv/psb_powermgmt.c | 10 --- 3 files changed, 89 insertions(+), 47 deletions(-) diff --git a/drivers/staging/mrst/drv/psb_intel_hdmi.c b/drivers/staging/mrst/drv/psb_intel_hdmi.c index 26ea0d6..f838e91 100644 --- a/drivers/staging/mrst/drv/psb_intel_hdmi.c +++ b/drivers/staging/mrst/drv/psb_intel_hdmi.c @@ -41,6 +41,7 @@ #include #include #include "mdfld_ti_tpd.h" +#include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) #include @@ -860,12 +861,13 @@ static void mdfld_hdmi_dpms(struct drm_encoder *encoder, int mode) static void mdfld_hdmi_encoder_save(struct drm_encoder *encoder) { - int dspcntr_reg = DSPBCNTR; - int dspbase_reg = MRST_DSPBBASE; struct drm_device *dev = encoder->dev; struct psb_intel_output *output = enc_to_psb_intel_output(encoder); struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; - u32 temp; + int dspcntr_reg = DSPBCNTR; + int dspbsurf_reg = DSPBSURF; + u32 dspbcntr_val; + PSB_DEBUG_ENTRY("\n"); if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, @@ -876,71 +878,114 @@ static void mdfld_hdmi_encoder_save(struct drm_encoder *encoder) /*Use Disable pipeB plane to turn off HDMI screen in early_suspend */ - temp = REG_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + dspbcntr_val = REG_READ(dspcntr_reg); + if ((dspbcntr_val & DISPLAY_PLANE_ENABLE) != 0) { REG_WRITE(dspcntr_reg, - temp & ~DISPLAY_PLANE_ENABLE); + dspbcntr_val & ~DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ - REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + REG_WRITE(dspbsurf_reg, REG_READ(dspbsurf_reg)); } ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } -static void mdfld_hdmi_encoder_restore(struct drm_encoder *encoder) +void mdfld_hdmi_encoder_restore_wq(struct work_struct *work) { + struct mid_intel_hdmi_priv *hdmi_priv = + container_of(work, struct mid_intel_hdmi_priv, enc_work.work); + struct drm_encoder *encoder; + struct drm_device *dev = NULL; + struct drm_psb_private *dev_priv = NULL; + struct psb_intel_output *output = NULL; int dspcntr_reg = DSPBCNTR; - int dspbase_reg = MRST_DSPBBASE; int dspbsurf_reg = DSPBSURF; - int dspblinoff_reg = DSPBLINOFF; - int dspbsize_reg = DSPBSIZE; - int dspbstride_reg = DSPBSTRIDE; - struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = - (struct drm_psb_private *)dev->dev_private; - struct psb_intel_output *output = enc_to_psb_intel_output(encoder); - struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; - u32 temp; + u32 dspcntr_val = 0; + PSB_DEBUG_ENTRY("\n"); - if(unlikely(!(hdmi_priv->need_encoder_restore))) + if (unlikely(!hdmi_priv)) return; - hdmi_priv->need_encoder_restore = false; + encoder = (struct drm_encoder *)hdmi_priv->data; + if (unlikely(!encoder)) + return; + + dev = (struct drm_device *)encoder->dev; + if (unlikely(!dev)) + return; + + dev_priv = dev->dev_private; + if (unlikely(!dev_priv)) + return; + + output = enc_to_psb_intel_output(encoder); + if (unlikely(!output)) + return; + + if (!drm_helper_encoder_in_use(encoder)) + return; + + if (unlikely(!hdmi_priv->need_encoder_restore)) + return; if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_FORCE_POWER_ON)) - return ; + return; - /*Set DSPBSURF to systemBuffer temporary to avoid hdmi display last picture*/ - REG_WRITE(dspbsurf_reg, dev_priv->init_screen_start); - REG_WRITE(dspblinoff_reg, dev_priv->init_screen_offset); - /* FIXME: this restore to init screen need to be replaced - * by flushing from upper layer. */ -#ifndef CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE - REG_WRITE(dspbsize_reg, dev_priv->init_screen_size); - REG_WRITE(dspbstride_reg, dev_priv->init_screen_stride); -#endif + if (!dev_priv->bhdmiconnected || + !(dev_priv->panel_desc & DISPLAY_B)) { + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); + return; + } - /*Restore pipe B plane to turn on HDMI screen - in late_resume*/ - temp = REG_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + /* Restore pipe B plane to turn on HDMI screen */ + dspcntr_val = REG_READ(dspcntr_reg); + if ((dspcntr_val & DISPLAY_PLANE_ENABLE) == 0 && + (DISP_PLANEB_STATUS != DISPLAY_PLANE_DISABLE)) { REG_WRITE(dspcntr_reg, - temp | DISPLAY_PLANE_ENABLE); + dspcntr_val | DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ - REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + REG_WRITE(dspbsurf_reg, REG_READ(dspbsurf_reg)); } + /*restore avi infomation*/ if (!dev_priv->bDVIport) mdfld_hdmi_set_avi_infoframe(dev, - &output->base, hdmi_priv->current_mode); + &output->base, hdmi_priv->current_mode); else { REG_WRITE(VIDEO_DIP_CTL, 0x0); REG_WRITE(AUDIO_DIP_CTL, 0x0); } + hdmi_priv->need_encoder_restore = false; + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); + + PSB_DEBUG_ENTRY("successfully\n"); +} + +static void mdfld_hdmi_encoder_restore(struct drm_encoder *encoder) +{ + unsigned long delay = 0; + struct drm_device *dev = NULL; + struct psb_intel_output *output = NULL; + struct mid_intel_hdmi_priv *hdmi_priv = NULL; + + if (unlikely(!encoder)) + return; + + output = enc_to_psb_intel_output(encoder); + if (unlikely(!output)) + return; + + hdmi_priv = output->dev_priv; + if (unlikely(!hdmi_priv)) + return; + + hdmi_priv->data = (void *)encoder; + + delay = HZ/5; + schedule_delayed_work(&hdmi_priv->enc_work, delay); } @@ -2172,6 +2217,9 @@ void mdfld_hdmi_init(struct drm_device *dev, } else if (IS_CTP(dev)) mdfld_ti_tpd_init(hdmi_priv); + /* initialize hdmi encoder restore delayed work */ + INIT_DELAYED_WORK(&hdmi_priv->enc_work, mdfld_hdmi_encoder_restore_wq); + drm_sysfs_connector_add(connector); return; } diff --git a/drivers/staging/mrst/drv/psb_intel_hdmi.h b/drivers/staging/mrst/drv/psb_intel_hdmi.h index d61f316..f72c210 100644 --- a/drivers/staging/mrst/drv/psb_intel_hdmi.h +++ b/drivers/staging/mrst/drv/psb_intel_hdmi.h @@ -928,6 +928,10 @@ struct mid_intel_hdmi_priv { bool is_hardcode_edid; struct drm_display_mode *current_mode; bool need_encoder_restore; + + /* for hdmi encoder restore work queue */ + struct delayed_work enc_work; + void *data; }; struct hdmi_edid_info { diff --git a/drivers/staging/mrst/drv/psb_powermgmt.c b/drivers/staging/mrst/drv/psb_powermgmt.c index e74facc..b816f8e 100644 --- a/drivers/staging/mrst/drv/psb_powermgmt.c +++ b/drivers/staging/mrst/drv/psb_powermgmt.c @@ -1997,16 +1997,6 @@ static void restore_panel_controll_back(struct drm_psb_private *dev_priv) __func__); } - if (dev_priv->panel_desc & DISPLAY_B) { - dspcntr_val = PSB_RVDC32(DSPBCNTR); - /* comply the status with HDMI DPMS */ - if (DISP_PLANEB_STATUS == DISPLAY_PLANE_DISABLE) - PSB_WVDC32(dspcntr_val - & ~DISPLAY_PLANE_ENABLE, DSPBCNTR); - else - PSB_WVDC32(dspcntr_val - | DISPLAY_PLANE_ENABLE, DSPBCNTR); - } if (dev_priv->pvr_screen_event_handler) dev_priv->pvr_screen_event_handler(dev, 1); gbdispstatus = true; -- 2.7.4