diff options
author | Sandor Yu <R01008@freescale.com> | 2012-02-29 18:09:00 +0800 |
---|---|---|
committer | Justin Waters <justin.waters@timesys.com> | 2012-07-03 16:57:42 -0400 |
commit | 5acfe50b8e7c628da681e8b8f9463e245d9bd5c3 (patch) | |
tree | 22abfc9413635861d9554fa7f409d3c7ae5cab82 /drivers | |
parent | 2ba378a207e41589eff8b5c6cf1508ffdbf07a4a (diff) |
ENGR00175700 System hang when change HDMI from XGA to 1080P with display blank
Change the vide mode from XGA to 1080P when display blank,
the system will hang.
It is cause by overflow interrupt will trigger when the video mode change,
but clean the interrupt status bit depend on pixewl clock.
In blank state the pixel clock is gating so the HDMI PHY can't work.
Signed-off-by: Sandor Yu <R01008@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/mxc_hdmi.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c index ef3ebd333e0f..3c1f8fd2eb81 100644 --- a/drivers/video/mxc_hdmi.c +++ b/drivers/video/mxc_hdmi.c @@ -166,6 +166,7 @@ struct mxc_hdmi { u8 edid[HDMI_EDID_LEN]; bool fb_reg; bool cable_plugin; + u8 blank; bool dft_mode_set; char *dft_mode_str; int default_bpp; @@ -1080,6 +1081,14 @@ static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi) dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); + /* Never do phy init if pixel clock is gated. + * Otherwise HDMI PHY will get messed up and generate an overflow + * interrupt that can't be cleared or detected by accessing the + * status register. */ + if (!hdmi->fb_reg || !hdmi->cable_plugin + || (hdmi->blank != FB_BLANK_UNBLANK)) + return; + /*check csc whether needed activated in HDMI mode */ cscon = (isColorSpaceConversion(hdmi) && !hdmi->hdmi_data.video_mode.mDVI); @@ -1701,8 +1710,7 @@ static void mxc_hdmi_cable_connected(struct mxc_hdmi *hdmi) static int mxc_hdmi_power_on(struct mxc_dispdrv_handle *disp) { struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp); - if (hdmi->fb_reg && hdmi->cable_plugin) - mxc_hdmi_phy_init(hdmi); + mxc_hdmi_phy_init(hdmi); return 0; } @@ -1889,7 +1897,7 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) return IRQ_HANDLED; } -static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) +static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event) { struct fb_videomode m; const struct fb_videomode *edid_mode; @@ -1899,8 +1907,10 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) fb_var_to_videomode(&m, &hdmi->fbi->var); dump_fb_videomode(&m); - /* Exit the setup if we are already set to this video mode */ - if (fb_mode_is_equal(&hdmi->previous_mode, &m)) { + /* Exit the setup if we get mode change and are already set to + * this video mode */ + if ((event == FB_EVENT_MODE_CHANGE) && + fb_mode_is_equal(&hdmi->previous_mode, &m)) { dev_dbg(&hdmi->pdev->dev, "%s video mode did not change.\n", __func__); mxc_hdmi_phy_init(hdmi); @@ -1908,8 +1918,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) } dev_dbg(&hdmi->pdev->dev, "%s - video mode changed\n", __func__); - hdmi_disable_overflow_interrupts(); - /* Save mode as 'previous_mode' so that we can know if mode changed. */ memcpy(&hdmi->previous_mode, &m, sizeof(struct fb_videomode)); @@ -1919,7 +1927,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) * vga default. */ memcpy(&hdmi->previous_non_vga_mode, &m, sizeof(struct fb_videomode)); - if (!list_empty(&hdmi->fbi->modelist)) { edid_mode = fb_find_nearest_mode(&m, &hdmi->fbi->modelist); pr_debug("edid mode "); @@ -1928,6 +1935,12 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) } } + /* Exit the setup if HDMI cable plugout or display blank */ + if (!hdmi->cable_plugin || (hdmi->blank != FB_BLANK_UNBLANK)) + return; + + hdmi_disable_overflow_interrupts(); + if (hdmi->vic == 0) { dev_dbg(&hdmi->pdev->dev, "Non-CEA mode used in HDMI\n"); hdmi->hdmi_data.video_mode.mDVI = true; @@ -2005,7 +2018,8 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi) hdmi_tx_hdcp_config(hdmi); mxc_hdmi_clear_overflow(); - if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mDVI) + + if (!hdmi->hdmi_data.video_mode.mDVI) hdmi_enable_overflow_interrupts(); dev_dbg(&hdmi->pdev->dev, "%s exit\n\n", __func__); @@ -2073,16 +2087,17 @@ static int mxc_hdmi_fb_event(struct notifier_block *nb, case FB_EVENT_MODE_CHANGE: dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_MODE_CHANGE\n"); if (hdmi->fb_reg) - mxc_hdmi_setup(hdmi); + mxc_hdmi_setup(hdmi, val); break; case FB_EVENT_BLANK: - if (*((int *)event->data) == FB_BLANK_UNBLANK) { + hdmi->blank = *((int *)event->data); + if (hdmi->blank == FB_BLANK_UNBLANK) { dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_BLANK - UNBLANK\n"); mxc_hdmi_enable_pins(hdmi); if (hdmi->fb_reg && hdmi->cable_plugin) - mxc_hdmi_setup(hdmi); + mxc_hdmi_setup(hdmi, val); } else { dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_BLANK - BLANK\n"); @@ -2100,8 +2115,7 @@ static int mxc_hdmi_fb_event(struct notifier_block *nb, case FB_EVENT_RESUME: dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_RESUME\n"); - if (hdmi->fb_reg && hdmi->cable_plugin) - mxc_hdmi_phy_init(hdmi); + mxc_hdmi_phy_init(hdmi); break; } |