From abe98868937126db864d3166bb7b9c8aa97671dc Mon Sep 17 00:00:00 2001 From: "Tong, Bo" Date: Tue, 17 Jan 2012 21:30:43 +0800 Subject: [PATCH] [Graphics/Display]: Port a bunch of patches from R2 BZ: 17008 This patch includes below bug fixing 0002-GFX-pvr-PVR-Vulnerability-kernel-part.patch: BZ:16572 0003-Gfx-Display-Remove-unecessary-checks-during-HDMI-aud.patch: BZ:15315 0004-Graphics-Perf-Don-t-touch-GL3-island-if-GL3-is-disab.patch: BZ:19285 0005-GFX-DISPLAY-flush-flip-queue-when-turnning-screen-of.patch: BZ:20078 0006-GFX-Display-fix-screen-black-screen-problem.patch: BZ:20280 0007-GFX-display-Correct-missing-HDMI-audio-interrupt-cas.patch: BZ:18865 0008-Gfx-Display-Solve-HDMI-mess-issue-when-setting-mode-.patch: BZ:19601 0007-GFX-Display-fix-HDMI-can-not-resume-issue-when-bench.patch BZ:13403 0008-GFX-Display-Fix-Maximum-Display-Timing-Determination.patch BZ:16583 0009-Gfx-Display-fix-issue-of-uninitialized-variable-in-p.patch BZ:15899 0010-Gfx-Display-Add-protection-for-DSPBCNTR-reg-access.patch BZ:16589 0011-Gfx-Display-Add-mutex-protection-for-Display-PIPE-B-.patch BZ:18201 0012-GFX-Display-display-plane-state-should-be-set-after-.patch BZ:18486 0013-Gfx-Display-invalidate-the-hdmi-mode-if-it-exceeds-D.patch BZ:18659 0014-GFX-Display-if-not-get-EDID-fix-hard-code-to-720.patch BZ:18659 0015-Gfx-Display-Fix-app-ANR-issue-when-suspend-resume-du.patch BZ:18681 0016-GFX-Display-fix-resume-abnormal-after-HDMI-unplug.patch BZ:16837 0017-GFX-Display-fix-DPMS-on-off-FIFO-not-empty-issue.patch BZ:18447 0018-Display-HDMI-Add-new-logic-to-parse-video-data-block.patch BZ:19218 0019-Gfx-Display-Add-print-in-EDID-reading-and-four-block.patch BZ:19218 Change-Id: I11e2b2c6b1ba9e7139b2460ede9328d27d63a3cf Signed-off-by: Tong, Bo Reviewed-on: http://android.intel.com:8080/32132 Reviewed-by: Lu, Liuhui Reviewed-by: buildbot Tested-by: buildbot --- drivers/gpu/drm/drm_edid.c | 2 + drivers/staging/mrst/drv/mdfld_dsi_dpi.c | 21 +- drivers/staging/mrst/drv/mdfld_dsi_output.c | 4 + drivers/staging/mrst/drv/mdfld_hdmi_audio.c | 20 +- drivers/staging/mrst/drv/psb_drm.h | 2 +- drivers/staging/mrst/drv/psb_drv.c | 32 ++- drivers/staging/mrst/drv/psb_drv.h | 6 +- drivers/staging/mrst/drv/psb_intel_display2.c | 108 +++++--- drivers/staging/mrst/drv/psb_intel_hdmi.c | 272 +++++++++++++++++++-- drivers/staging/mrst/drv/psb_intel_hdmi.h | 34 +++ drivers/staging/mrst/drv/psb_intel_reg.h | 6 + drivers/staging/mrst/drv/psb_irq.c | 28 ++- drivers/staging/mrst/drv/psb_powermgmt.c | 63 ++++- drivers/staging/mrst/drv/psb_powermgmt.h | 2 + drivers/staging/mrst/drv/tmd_6x10_vid.c | 4 +- .../3rdparty/linux_framebuffer_drm/drmlfb.h | 2 + .../linux_framebuffer_drm/drmlfb_displayclass.c | 29 ++- .../services4/srvkm/bridged/bridged_pvr_bridge.c | 1 - 18 files changed, 525 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6482dab..c0e8612 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -331,6 +331,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) if (i == 4) goto carp; + print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, block, EDID_LENGTH); /* if there's no extensions, we're done */ if (block[0x7e] == 0) return block; @@ -346,6 +347,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; + print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, block+j*EDID_LENGTH, EDID_LENGTH); if (j < 2) { if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) { valid_extensions++; diff --git a/drivers/staging/mrst/drv/mdfld_dsi_dpi.c b/drivers/staging/mrst/drv/mdfld_dsi_dpi.c index a4f26a2..28e17a4 100755 --- a/drivers/staging/mrst/drv/mdfld_dsi_dpi.c +++ b/drivers/staging/mrst/drv/mdfld_dsi_dpi.c @@ -1559,8 +1559,7 @@ static int __mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) mutex_lock(&dsi_config->context_lock); if (on && !dsi_config->dsi_hw_context.panel_on) { - /*Just turn on panel for WiDi Extended Mode.*/ - if (!dev_priv->drm_psb_widi) { + if (!dev_priv->drm_psb_widi && !dev_priv->dpms_on_off) { if (__dpi_panel_power_on(dsi_config, p_funcs)) { DRM_ERROR("Failed to power on\n"); goto set_power_err; @@ -1583,7 +1582,7 @@ static int __mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) goto set_power_err; } /*Just turn off panel for WiDi Extended Mode.*/ - if (!dev_priv->drm_psb_widi) { + if (!dev_priv->drm_psb_widi && !dev_priv->dpms_on_off) { if (__dpi_panel_power_off(dsi_config, p_funcs)) { DRM_ERROR("Failed to power off\n"); goto set_power_err; @@ -1702,18 +1701,32 @@ void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode) { + struct mdfld_dsi_encoder *dsi_encoder; + struct mdfld_dsi_config *dsi_config; + struct drm_device *dev; + struct drm_psb_private *dev_priv; + + dsi_encoder = MDFLD_DSI_ENCODER(encoder); + dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); + dev = dsi_config->dev; + dev_priv = dev->dev_private; + PSB_DEBUG_ENTRY( - "%s\n", (mode == DRM_MODE_DPMS_ON ? "on" : "off")); + "%s\n", (mode == DRM_MODE_DPMS_ON ? "on" : "off")); if (!gbdispstatus) { PSB_DEBUG_ENTRY( "panel in suspend status, skip turn on/off from DMPS"); return ; } + mutex_lock(&dev_priv->dpms_mutex); + dev_priv->dpms_on_off = true; if (mode == DRM_MODE_DPMS_ON) mdfld_dsi_dpi_set_power(encoder, true); else mdfld_dsi_dpi_set_power(encoder, false); + dev_priv->dpms_on_off = false; + mutex_unlock(&dev_priv->dpms_mutex); } bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, diff --git a/drivers/staging/mrst/drv/mdfld_dsi_output.c b/drivers/staging/mrst/drv/mdfld_dsi_output.c index ecea16d..1c53465 100755 --- a/drivers/staging/mrst/drv/mdfld_dsi_output.c +++ b/drivers/staging/mrst/drv/mdfld_dsi_output.c @@ -625,6 +625,9 @@ static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) panel_on2 = dev_priv->dbi_panel_on2; } + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_ONLY_IF_ON)) + return ; /*then check all display panels + monitors status*/ if(!panel_on && !panel_on2 && !(REG_READ(HDMIB_CONTROL) & HDMIB_PORT_EN)) { /*request rpm idle*/ @@ -643,6 +646,7 @@ static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) if(!dev_priv->rpm_enabled && !is_panel_vid_or_cmd(dev)) ospm_runtime_pm_allow(dev); #endif + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); #endif } diff --git a/drivers/staging/mrst/drv/mdfld_hdmi_audio.c b/drivers/staging/mrst/drv/mdfld_hdmi_audio.c index 575d4f7..545287d 100644 --- a/drivers/staging/mrst/drv/mdfld_hdmi_audio.c +++ b/drivers/staging/mrst/drv/mdfld_hdmi_audio.c @@ -174,10 +174,8 @@ static int mdfld_hdmi_audio_set_caps (enum had_caps_list set_element, void *capa if (*((u32*)capabilties) & HDMI_AUDIO_BUFFER_DONE) int_masks |= PIPE_HDMI_AUDIO_BUFFER_DONE; - if (dev_priv->hdmi_audio_interrupt_mask != int_masks) { - dev_priv->hdmi_audio_interrupt_mask |= int_masks; - mdfld_irq_enable_hdmi_audio(dev); - } + dev_priv->hdmi_audio_interrupt_mask |= int_masks; + mdfld_irq_enable_hdmi_audio(dev); break; case HAD_SET_DISABLE_AUDIO_INT: @@ -187,14 +185,12 @@ static int mdfld_hdmi_audio_set_caps (enum had_caps_list set_element, void *capa if (*((u32*)capabilties) & HDMI_AUDIO_BUFFER_DONE) int_masks |= PIPE_HDMI_AUDIO_BUFFER_DONE; - if (dev_priv->hdmi_audio_interrupt_mask & int_masks) { - dev_priv->hdmi_audio_interrupt_mask &= ~int_masks; - - if (dev_priv->hdmi_audio_interrupt_mask) - mdfld_irq_enable_hdmi_audio(dev); - else - mdfld_irq_disable_hdmi_audio(dev); - } + dev_priv->hdmi_audio_interrupt_mask &= ~int_masks; + + if (dev_priv->hdmi_audio_interrupt_mask) + mdfld_irq_enable_hdmi_audio(dev); + else + mdfld_irq_disable_hdmi_audio(dev); break; default: diff --git a/drivers/staging/mrst/drv/psb_drm.h b/drivers/staging/mrst/drv/psb_drm.h index 7ba6a4d..e63b0bd 100644 --- a/drivers/staging/mrst/drv/psb_drm.h +++ b/drivers/staging/mrst/drv/psb_drm.h @@ -43,7 +43,7 @@ * c - Hotfix Release * xxxx - Graphics internal build # */ -#define PSB_PACKAGE_VERSION "5.6.0.1153" +#define PSB_PACKAGE_VERSION "5.6.0.1202" #define DRM_PSB_SAREA_MAJOR 0 #define DRM_PSB_SAREA_MINOR 2 diff --git a/drivers/staging/mrst/drv/psb_drv.c b/drivers/staging/mrst/drv/psb_drv.c index c1681aa..48e2efe 100644 --- a/drivers/staging/mrst/drv/psb_drv.c +++ b/drivers/staging/mrst/drv/psb_drv.c @@ -1094,6 +1094,11 @@ void hdmi_do_hotplug_wq(struct work_struct *work) struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private, hdmi_hotplug_wq); + + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return; + atomic_inc(&dev_priv->hotplug_wq_done); /* notify user space of hotplug event via a uevent message */ @@ -1125,16 +1130,15 @@ void hdmi_do_hotplug_wq(struct work_struct *work) PSB_DEBUG_ENTRY( "hdmi_do_hotplug_wq: HDMI unplugged\n"); dev_priv->bhdmiconnected = false; hdmi_state = 0; - - drm_sysfs_hotplug_event(dev_priv->dev); - if (dev_priv->mdfld_had_event_callbacks) (*dev_priv->mdfld_had_event_callbacks) (HAD_EVENT_HOT_UNPLUG, dev_priv->had_pvt_data); + drm_sysfs_hotplug_event(dev_priv->dev); } #endif atomic_dec(&dev_priv->hotplug_wq_done); + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } void hdmi_do_audio_wq(struct work_struct *work) @@ -1434,6 +1438,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) hdmi_state = 0; dev_priv->bhdmiconnected = false; + dev_priv->dpms_on_off = false; #ifdef CONFIG_MDFD_VIDEO_DECODE ret = psb_ttm_global_init(dev_priv); @@ -1450,6 +1455,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) mutex_init(&dev_priv->temp_mem); mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->reset_mutex); + mutex_init(&dev_priv->dpms_mutex); INIT_LIST_HEAD(&dev_priv->context.validate_list); INIT_LIST_HEAD(&dev_priv->context.kern_validate_list); @@ -1981,6 +1987,9 @@ static int psb_disp_ioctl(struct drm_device *dev, void *data, if (DISP_PLANEB_STATUS == DISPLAY_PLANE_DISABLE) ret = -1; else { + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_ONLY_IF_ON)) { + return -1; + } /*Use Disable pipeB plane to turn off HDMI screen*/ temp = REG_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) != 0) { @@ -1989,11 +1998,16 @@ static int psb_disp_ioctl(struct drm_device *dev, void *data, /* Flush the plane changes */ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); } + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } } else if (dp_ctrl->cmd == DRM_PSB_DISP_PLANEB_ENABLE) { if (DISP_PLANEB_STATUS == DISPLAY_PLANE_DISABLE) ret = -1; else { + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_ONLY_IF_ON)) { + return -1; + } /*Restore pipe B plane to turn on HDMI screen*/ temp = REG_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) == 0) { @@ -2002,13 +2016,18 @@ static int psb_disp_ioctl(struct drm_device *dev, void *data, /* Flush the plane changes */ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); } + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } } else if (dp_ctrl->cmd == DRM_PSB_HDMI_OSPM_ISLAND_DOWN) { /*Set power state island down when hdmi disconnected */ + acquire_ospm_lock(); if (pmu_nc_set_power_state(OSPM_DISPLAY_B_ISLAND, OSPM_ISLAND_DOWN, OSPM_REG_TYPE)) BUG(); dev_priv->panel_desc &= ~DISPLAY_B; + DISP_PLANEB_STATUS = ~DISPLAY_PLANE_ENABLE; + release_ospm_lock(); } exit: return ret; @@ -2202,6 +2221,7 @@ static int psb_hist_enable_ioctl(struct drm_device *dev, void *data, struct dpst_guardband guardband_reg; struct dpst_ie_histogram_control ie_hist_cont_reg; uint32_t *enable = data; + unsigned long irq_flags; if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_ONLY_IF_ON)) { return 0; @@ -2219,8 +2239,10 @@ static int psb_hist_enable_ioctl(struct drm_device *dev, void *data, guardband_reg.interrupt_status = 1; PSB_WVDC32(guardband_reg.data, HISTOGRAM_INT_CONTROL); + spin_lock_irqsave(&dev_priv->irqmask_lock, irq_flags); irqCtrl = PSB_RVDC32(PIPEASTAT); PSB_WVDC32(irqCtrl | PIPE_DPST_EVENT_ENABLE, PIPEASTAT); + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irq_flags); /* Wait for two vblanks */ } else { guardband_reg.data = PSB_RVDC32(HISTOGRAM_INT_CONTROL); @@ -2232,9 +2254,11 @@ static int psb_hist_enable_ioctl(struct drm_device *dev, void *data, ie_hist_cont_reg.ie_histogram_enable = 0; PSB_WVDC32(ie_hist_cont_reg.data, HISTOGRAM_LOGIC_CONTROL); + spin_lock_irqsave(&dev_priv->irqmask_lock, irq_flags); irqCtrl = PSB_RVDC32(PIPEASTAT); irqCtrl &= ~PIPE_DPST_EVENT_ENABLE; PSB_WVDC32(irqCtrl, PIPEASTAT); + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irq_flags); } ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); @@ -3675,6 +3699,8 @@ static const struct dev_pm_ops psb_pm_ops = { .runtime_suspend = psb_runtime_suspend, .runtime_resume = psb_runtime_resume, .runtime_idle = psb_runtime_idle, + .suspend = psb_runtime_suspend, + .resume = psb_runtime_resume, }; static struct drm_driver driver = { diff --git a/drivers/staging/mrst/drv/psb_drv.h b/drivers/staging/mrst/drv/psb_drv.h index 26d1284..ab821d4 100644 --- a/drivers/staging/mrst/drv/psb_drv.h +++ b/drivers/staging/mrst/drv/psb_drv.h @@ -396,6 +396,7 @@ struct psb_video_ctx { }; typedef int (*pfn_vsync_handler)(struct drm_device* dev, int pipe); +typedef int(* pfn_screen_event_handler)(struct drm_device* psDrmDevice, int state); #define MODE_SETTING_IN_CRTC 0x1 @@ -1054,7 +1055,10 @@ struct drm_psb_private { /*hdmi connected status */ bool bhdmiconnected; - + bool dpms_on_off; + struct workqueue_struct *hpd_detect; + pfn_screen_event_handler pvr_screen_event_handler; + struct mutex dpms_mutex; }; struct psb_fpriv { diff --git a/drivers/staging/mrst/drv/psb_intel_display2.c b/drivers/staging/mrst/drv/psb_intel_display2.c index d18a82a..9805c75 100755 --- a/drivers/staging/mrst/drv/psb_intel_display2.c +++ b/drivers/staging/mrst/drv/psb_intel_display2.c @@ -335,6 +335,25 @@ void mdfld__intel_plane_set_alpha(int enable) REG_WRITE(dspcntr_reg, dspcntr); } +static void pfit_landscape(struct drm_device *dev, + int hsrc_sz, int vsrc_sz, + int hdst_sz, int vdst_sz) +{ + int hscale = 0, vscale = 0; + + REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | PFIT_PIPE_SELECT_B | + PFIT_SCALING_MODE_PROGRAM); + + hscale = PFIT_FRACTIONAL_VALUE * (hsrc_sz + 1) / (hdst_sz + 1); + vscale = PFIT_FRACTIONAL_VALUE * (vsrc_sz + 1) / (vdst_sz + 1); + + PSB_DEBUG_ENTRY("hscale = 0x%X, vscale = 0X%X\n", hscale, vscale); + + REG_WRITE(PFIT_PGM_RATIOS, + hscale << PFIT_HORIZ_SCALE_SHIFT | + vscale << PFIT_VERT_SCALE_SHIFT); +} + static int mdfld_intel_set_scaling_property(struct drm_crtc *crtc, int x, int y, int pipe) { struct drm_device *dev = crtc->dev; @@ -409,48 +428,57 @@ static int mdfld_intel_set_scaling_property(struct drm_crtc *crtc, int x, int y, break; case DRM_MODE_SCALE_ASPECT: - if ((adjusted_mode->hdisplay - sprite_width) >= - (adjusted_mode->vdisplay -sprite_height)) { - src_image_hor = adjusted_mode->hdisplay * - sprite_height /adjusted_mode->vdisplay; - src_image_vert = sprite_height; - sprite_pos_x = - (adjusted_mode->hdisplay - sprite_width) * - sprite_height /adjusted_mode->vdisplay /2; - sprite_pos_y = 0; - } else { - src_image_hor = sprite_width; - src_image_vert = adjusted_mode->vdisplay * - sprite_width / - adjusted_mode->hdisplay; - sprite_pos_x = 0; - sprite_pos_y = - (adjusted_mode->vdisplay - sprite_height) * - sprite_width /adjusted_mode->hdisplay /2; - } - - /* In case of rotation to landscape mode or hdmi timing - * setting is less than framebuffer size, it scales to - * hdmi display timing size automatically. - */ - if ((fb->width > fb->height) || - (fb->width > adjusted_mode->hdisplay) || - (fb->height > adjusted_mode->vdisplay)) { - sprite_pos_x = 0; - sprite_pos_y = 0; - sprite_height = fb->height; - sprite_width = fb->width; - src_image_hor = fb->width; - src_image_vert = fb->height; - } + sprite_pos_x = 0; + sprite_pos_y = 0; + sprite_height = fb->height; + sprite_width = fb->width; + src_image_hor = fb->width; + src_image_vert = fb->height; + /* Use panel fitting when the display does not match + * with the framebuffer size */ if ((adjusted_mode->hdisplay != fb->width) || - (adjusted_mode->vdisplay != - fb->height)) - REG_WRITE(PFIT_CONTROL, - PFIT_ENABLE | - PFIT_PIPE_SELECT_B | - PFIT_SCALING_MODE_AUTO); + (adjusted_mode->vdisplay != fb->height)) { + if (fb->width > fb->height) { + pr_debug("[hdmi]: Landscape mode...\n"); + /* Landscape mode: program ratios is + * used because 480p does not work with + * auto */ + if (adjusted_mode->vdisplay == 480) + pfit_landscape(dev, + sprite_width, + sprite_height, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay); + else + REG_WRITE(PFIT_CONTROL, + PFIT_ENABLE | + PFIT_PIPE_SELECT_B | + PFIT_SCALING_MODE_AUTO); + } else { + /* Portrait mode */ + pr_debug("[hdmi]: Portrait mode...\n"); + if (adjusted_mode->vdisplay == 768 && + adjusted_mode->hdisplay == 1024) { + src_image_hor = adjusted_mode->hdisplay * + fb->height / + adjusted_mode->vdisplay; + src_image_vert = fb->height; + sprite_pos_x = (src_image_hor - fb->width) / 2; + REG_WRITE(PFIT_CONTROL, + PFIT_ENABLE | + PFIT_PIPE_SELECT_B | + PFIT_SCALING_MODE_AUTO); + } else + REG_WRITE(PFIT_CONTROL, + PFIT_ENABLE | + PFIT_PIPE_SELECT_B | + PFIT_SCALING_MODE_PILLARBOX); + } + } else { + /* Disable panel fitting */ + REG_WRITE(PFIT_CONTROL, 0); + } break; default: diff --git a/drivers/staging/mrst/drv/psb_intel_hdmi.c b/drivers/staging/mrst/drv/psb_intel_hdmi.c index c4aac77..9d04c89 100644 --- a/drivers/staging/mrst/drv/psb_intel_hdmi.c +++ b/drivers/staging/mrst/drv/psb_intel_hdmi.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "psb_intel_drv.h" #include "psb_drv.h" #include "psb_irq.h" @@ -142,7 +143,7 @@ char EDID_Toshiba_Regza[EDID_LENGTH + HDMI_CEA_EDID_BLOCK_SIZE] = 0x10, 0x3e, 0x96, 0x00, 0xc4, 0x8e, 0x21, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x53, 0x42, 0x2d, 0x54, 0x56, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x17, 0x3d, 0x0f, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x03, - 0x02, 0x03, 0x20, 0x77, 0x4a, 0x90, 0x05, 0x04, 0x03, 0x07, 0x02, 0x06, 0x01, 0x20, 0x22, 0x23, + 0x02, 0x03, 0x20, 0x77, 0x4a, 0x90, 0x05, 0x04, 0x03, 0x07, 0x02, 0x06, 0x01, 0x16, 0x15, 0x23, 0x09, 0x07, 0x07, 0x6c, 0x03, 0x0c, 0x00, 0x30, 0x00, 0x00, 0x1e, 0xc0, 0x2b, 0x2b, 0x33, 0x33, 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 0xc4, 0x8e, 0x21, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xa0, 0x14, 0x51, 0xf0, 0x16, 0x00, 0x26, 0x7c, 0x43, 0x00, 0xc4, 0x8e, @@ -160,6 +161,53 @@ static struct hdmi_edid_info mdfld_hdmi_edid[] = { { HDMI_EDID_INFO("TOSHIBA_32RV525RZ", EDID_Toshiba_32RV525RZ) }, { HDMI_EDID_INFO("TOSHIBA_REGZA", EDID_Toshiba_Regza) }, }; + +mdfld_hdmi_timing_t mdfld_hdmi_video_mode_table[] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 16 */ + {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 1080p/24 */ + {1920, 1080, 24, 74250, 2750, 1920, 2750, 2558, 2602, 1125, 1080, 1125, 1084, 1089}, + /* 1080p/25 */ + {1920, 1080, 25, 74250, 2640, 1920, 2640, 2448, 2492, 1125, 1080, 1125, 1084, 1089}, + /* 1080p/30 */ + {1920, 1080, 30, 74250, 2200, 1920, 2200, 2008, 2052, 1125, 1080, 1125, 1084, 1089}, + {35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + /* *VIC for AVI InfoFrame Data Byte 4 and CEA Short Descriptors */ @@ -347,9 +395,13 @@ static int mdfld_hdmi_set_avi_infoframe(struct drm_device *dev, u32 *p_vsif = (u32 *)&avi_if; PSB_DEBUG_ENTRY("%s\n", __func__); + /*get edid infomation*/ - cea_edid_block = (ce_edid_t *)(edid_block + EDID_BLOCK_SIZE); - base_edid_block = (baseedid_1_4_t *)edid_block; + if (connector && connector->edid_blob_ptr) { + edid_block = connector->edid_blob_ptr->data; + cea_edid_block = (ce_edid_t *)(edid_block + EDID_BLOCK_SIZE); + base_edid_block = (baseedid_1_4_t *)edid_block; + } /*set header information*/ avi_if.avi_info.avi_if_header.type = HDMI_AVI_TYPE; @@ -389,7 +441,8 @@ static int mdfld_hdmi_set_avi_infoframe(struct drm_device *dev, picture_aspect_ratio = mdfld_hdmi_get_aspect_ratio( mode->width_mm, mode->height_mm); PSB_DEBUG_ENTRY("PAR caculate by width_mm.\n"); - } else if (base_edid_block->ucMaxHIS && + } else if (base_edid_block && + base_edid_block->ucMaxHIS && base_edid_block->ucMaxVIS) { picture_aspect_ratio = mdfld_hdmi_get_aspect_ratio( base_edid_block->ucMaxHIS, @@ -534,6 +587,10 @@ static void mdfld_hdmi_mode_set(struct drm_encoder *encoder, PSB_DEBUG_ENTRY("\n"); + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + hdmi_phy_misc = REG_READ(HDMIPHYMISCCTL) & ~HDMI_PHY_POWER_DOWN; REG_WRITE(HDMIPHYMISCCTL, hdmi_phy_misc); @@ -604,6 +661,8 @@ static void mdfld_hdmi_mode_set(struct drm_encoder *encoder, (*dev_priv->mdfld_had_event_callbacks)(event_type, had_pvt_data); #endif + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); + return; } @@ -715,6 +774,10 @@ static void mdfld_hdmi_dpms(struct drm_encoder *encoder, int mode) PSB_DEBUG_ENTRY("%s\n", mode == DRM_MODE_DPMS_ON ? "on" : "off"); + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + hdmib = REG_READ(hdmi_priv->hdmib_reg) | HDMIB_PIPE_B_SELECT; if (dev_priv->bDVIport) { @@ -750,6 +813,8 @@ static void mdfld_hdmi_dpms(struct drm_encoder *encoder, int mode) (HAD_EVENT_HOT_PLUG, dev_priv->had_pvt_data); } REG_READ(hdmi_priv->hdmib_reg); + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } static void mdfld_hdmi_encoder_save(struct drm_encoder *encoder) @@ -760,6 +825,10 @@ static void mdfld_hdmi_encoder_save(struct drm_encoder *encoder) u32 temp; PSB_DEBUG_ENTRY("\n"); + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + /*Use Disable pipeB plane to turn off HDMI screen in early_suspend */ temp = REG_READ(dspcntr_reg); @@ -769,6 +838,8 @@ static void mdfld_hdmi_encoder_save(struct drm_encoder *encoder) /* Flush the plane changes */ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); } + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } static void mdfld_hdmi_encoder_restore(struct drm_encoder *encoder) @@ -783,6 +854,10 @@ static void mdfld_hdmi_encoder_restore(struct drm_encoder *encoder) u32 temp; PSB_DEBUG_ENTRY("\n"); + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + /*Restore pipe B plane to turn on HDMI screen in late_resume*/ temp = REG_READ(dspcntr_reg); @@ -800,6 +875,8 @@ static void mdfld_hdmi_encoder_restore(struct drm_encoder *encoder) REG_WRITE(VIDEO_DIP_CTL, 0x0); REG_WRITE(AUDIO_DIP_CTL, 0x0); } + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } @@ -810,7 +887,13 @@ static void mdfld_hdmi_connector_save(struct drm_connector *connector) struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; PSB_DEBUG_ENTRY("\n"); + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmib_reg); + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } static void mdfld_hdmi_connector_restore(struct drm_connector *connector) @@ -820,8 +903,15 @@ static void mdfld_hdmi_connector_restore(struct drm_connector *connector) struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; PSB_DEBUG_ENTRY("\n"); + + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + REG_WRITE(hdmi_priv->hdmib_reg, hdmi_priv->save_HDMIB); REG_READ(hdmi_priv->hdmib_reg); + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } /* HDMI DIP related stuff */ @@ -1244,6 +1334,7 @@ mdfld_hdmi_edid_detect(struct drm_connector *connector) } if (i == monitor_number) { +#if HDMI_COMPLIANCE_TEST if (!((IS_MDFLD_OLD(dev)) && (dev_priv->platform_rev_id < MDFLD_PNW_C0))) { PSB_DEBUG_ENTRY( @@ -1251,7 +1342,9 @@ mdfld_hdmi_edid_detect(struct drm_connector *connector) /*EDID_Samsung_2493HM*/ edid = (struct edid *)mdfld_hdmi_edid[1].edid_info; - } else { + } else +#endif + { PSB_DEBUG_ENTRY( "hard code fix to HDMI!\n"); /*Use Toshiba Regza HDMI EDID as default data.*/ @@ -1364,8 +1457,9 @@ static enum drm_connector_status mdfld_hdmi_detect(struct drm_connector } } else { - DRM_DEBUG("%s: HPD disconnected data = 0x%x.\n", __func__, + PSB_DEBUG_ENTRY("%s: HPD disconnected data = 0x%x.\n", __func__, data); + connect_status = connector_status_disconnected; if (dev_priv->panel_desc & DISPLAY_B) { hdmi_unplug_prepare(dev_priv); @@ -1378,7 +1472,6 @@ static enum drm_connector_status mdfld_hdmi_detect(struct drm_connector */ drm_helper_disable_unused_functions(dev); } - connect_status = connector_status_disconnected; } } /* IS_MDFLD_OLD(dev) code */ @@ -1416,8 +1509,8 @@ static int mdfld_hdmi_set_property(struct drm_connector *connector, if (!strcmp(property->name, "scaling mode") && pEncoder) { struct psb_intel_crtc *pPsbCrtc = to_psb_intel_crtc(pEncoder->crtc); - bool bTransitionFromToCentered; - bool bTransitionFromToAspect; + bool bTransitionFromToCentered = false; + bool bTransitionFromToAspect = false; uint64_t curValue; if (!pPsbCrtc) @@ -1447,7 +1540,7 @@ static int mdfld_hdmi_set_property(struct drm_connector *connector, bTransitionFromToCentered = (curValue == DRM_MODE_SCALE_NO_SCALE) || (value == DRM_MODE_SCALE_NO_SCALE) || (curValue == DRM_MODE_SCALE_CENTER) || (value == DRM_MODE_SCALE_CENTER); - bTransitionFromToCentered = (curValue == DRM_MODE_SCALE_ASPECT) || + bTransitionFromToAspect = (curValue == DRM_MODE_SCALE_ASPECT) || (value == DRM_MODE_SCALE_ASPECT); if (pPsbCrtc->saved_mode.hdisplay != 0 && @@ -1503,6 +1596,116 @@ static int mdfld_hdmi_get_hardcoded_edid_modes(struct drm_connector *connector) return ret; } +int mdfld_add_eedid_video_block_modes(struct drm_connector *connector, struct edid *edid) +{ + struct drm_device *dev = connector->dev; + int i, j, modes = 0; + char *edid_ext = NULL; + u32 quirks = 0; + struct detailed_timing *timing; + extention_block_cea_t eb; + unsigned char *c = eb.data; + int vic; + mdfld_hdmi_timing_t *p_video_mode; + struct detailed_timing * vblock_timings; + struct drm_display_mode *mode; + int block_type, payload_size; + int start_offset, end_offset; + + if (edid->version == 1 && edid->revision < 3) + return 0; + if (!edid->extensions) + return 0; + + /* Find CEA extension */ + for (i = 0; i < edid->extensions; i++) { + edid_ext = (char *)edid + EDID_LENGTH * (i + 1); + + /* Extended EDID BLOCK */ + if (edid_ext[0] == 0x02) { + memset(&eb, 0, sizeof(extention_block_cea_t)); + + if (edid_ext != NULL) + memcpy(&eb, edid_ext, sizeof(extention_block_cea_t)); + + printk("CEA tag = %X, revision = %X, content_offset = %X, flags = %X\n", eb.tag, eb.revision, eb.content_offset, eb.flags); + + /* + * Short descriptors section exists when: + * - offset is not 4 + * - CEA extension version is 3 + */ + if ((eb.content_offset != 4) && (eb.revision >= 3)) { + + c = eb.data; + /* All area before detailed descriptors should be filled + * TODO: Shall we change this to safer check? + */ + while (c < ((unsigned char *)&eb + eb.content_offset)) { + block_type = (*c & 0xE0) >> 5; + payload_size = *c & 0x1F; + + printk("block_type: %d, payload_size: %d\n", block_type, payload_size); + /* Simple block types */ + switch (block_type) { + case 0: + break; + case 1: + break; + case 2: + for (j = 1; j < payload_size+1; j++) { + vic = *(c + j) & 0x7F; + + printk("vic: %d\n", vic); + if (vic == 34 || vic == 32 || vic == 33) { + p_video_mode = &mdfld_hdmi_video_mode_table[vic - 1]; + + mode = drm_mode_create(dev); + if (!mode) + return NULL; + + mode->type = DRM_MODE_TYPE_DRIVER; + + mode->vrefresh = p_video_mode->refresh; + mode->clock = p_video_mode->dclk; + + mode->hdisplay = p_video_mode->width; + mode->hsync_start = p_video_mode->hsync_start; + mode->hsync_end = p_video_mode->hsync_end; + mode->htotal = p_video_mode->htotal; + + mode->vdisplay = p_video_mode->height; + mode->vsync_start = p_video_mode->vsync_start; + mode->vsync_end = p_video_mode->vsync_end; + mode->vtotal = p_video_mode->vtotal; + + mode->flags = 0; + + drm_mode_set_name(mode); + + mode->width_mm = 1600; + mode->height_mm = 900; + + printk("VIDEO TIMING. hdisplay = %d, vdisplay = %d.\n", + mode->hdisplay, mode->vdisplay); + + drm_mode_probed_add(connector, mode); + modes++; + } + } + break; + default: + break; + } + c += (*c & 0x1F) + 1; + } /* end of while */ + } + } + } /* end of for loop */ + + return modes; +} + static int mdfld_hdmi_get_modes(struct drm_connector *connector) { struct psb_intel_output *psb_intel_output = to_psb_intel_output(connector); @@ -1541,6 +1744,7 @@ static int mdfld_hdmi_get_modes(struct drm_connector *connector) if (edid) { ret = drm_add_edid_modes(&psb_intel_output->base, edid); + ret += mdfld_add_eedid_video_block_modes(&psb_intel_output->base, edid); } else if (IS_CTP(dev)) { /* try one more time to get edid here */ edid = drm_get_edid(&psb_intel_output->base, @@ -1609,8 +1813,13 @@ static int mdfld_hdmi_get_modes(struct drm_connector *connector) " set hardcode edid prefer to 640*480p\n"); list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { +#if HDMI_COMPLIANCE_TEST if (mode->hdisplay == 640 && mode->vdisplay == 480) +#else + if (mode->hdisplay == 1280 + && mode->vdisplay == 720) +#endif mode->type |= DRM_MODE_TYPE_PREFERRED; else if (mode->type & DRM_MODE_TYPE_PREFERRED) @@ -1635,16 +1844,18 @@ static int mdfld_hdmi_get_modes(struct drm_connector *connector) /*clear the mode ,which the same as preferred mode otherwise the preferred mode will be updated by the same mode in DRM */ - list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { - if ((!(mode->type & DRM_MODE_TYPE_PREFERRED)) && - drm_mode_equal(mode, - hdmi_priv->edid_preferred_mode)) { - PSB_DEBUG_ENTRY( - "clear the same mode as preferred.\n"); - list_del(&mode->head); - drm_mode_destroy(dev, mode); - } - } + if (hdmi_priv->edid_preferred_mode != NULL) { + list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { + if ((!(mode->type & DRM_MODE_TYPE_PREFERRED)) && + drm_mode_equal(mode, + hdmi_priv->edid_preferred_mode)) { + PSB_DEBUG_ENTRY( + "clear the same mode as preferred.\n"); + list_del(&mode->head); + drm_mode_destroy(dev, mode); + } + } + } return ret; } @@ -1652,12 +1863,15 @@ static int mdfld_hdmi_get_modes(struct drm_connector *connector) static int mdfld_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct psb_intel_output *psb_intel_output = - to_psb_intel_output(connector); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_output->dev_priv; + PSB_DEBUG_ENTRY("display info. hdisplay = %d, vdisplay = %d, vrefresh = %d.\n", + mode->hdisplay, mode->vdisplay, mode->vrefresh); - PSB_DEBUG_ENTRY("display info. hdisplay = %d, vdisplay = %d.\n", - mode->hdisplay, mode->vdisplay); + /* change the maximum clock to be 74.25mhz per DC spec */ + if (mode->clock > 74250) + return MODE_CLOCK_HIGH; + + if (mode->clock < 20000) + return MODE_CLOCK_LOW; if (mode->type == DRM_MODE_TYPE_USERDEF) return MODE_OK; @@ -1683,8 +1897,14 @@ static void mdfld_hdmi_connector_dpms(struct drm_connector *connector, int mode) #ifdef CONFIG_PM_RUNTIME bool panel_on, panel_on2; #endif + + if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, + OSPM_UHB_FORCE_POWER_ON)) + return ; + /*first, execute dpms*/ /* using suspend to judge whether hdmi audio is playing */ + hdmi_audio_event.event = 0; if (dev_priv->had_interface && dev_priv->had_pvt_data) hdmi_audio_busy = dev_priv->had_interface->suspend(dev_priv->had_pvt_data, @@ -1719,6 +1939,7 @@ static void mdfld_hdmi_connector_dpms(struct drm_connector *connector, int mode) } + #ifdef CONFIG_PM_RUNTIME if(is_panel_vid_or_cmd(dev)) { /*DPI panel*/ @@ -1749,6 +1970,7 @@ static void mdfld_hdmi_connector_dpms(struct drm_connector *connector, int mode) ospm_runtime_pm_allow(dev); #endif #endif + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); } static const struct drm_encoder_helper_funcs mdfld_hdmi_helper_funcs = { diff --git a/drivers/staging/mrst/drv/psb_intel_hdmi.h b/drivers/staging/mrst/drv/psb_intel_hdmi.h index 5025973..2673a9b 100644 --- a/drivers/staging/mrst/drv/psb_intel_hdmi.h +++ b/drivers/staging/mrst/drv/psb_intel_hdmi.h @@ -393,6 +393,28 @@ struct hdmi_video_format_timing { avi_par_info_t par; }; +/** + * Display timing information + */ +typedef struct { + unsigned short width; /* width */ + unsigned short height; /* height */ + unsigned short refresh; /* refresh rate */ + unsigned long dclk; /* refresh rate dot clock in kHz */ + unsigned short htotal; /* horizontal total */ + unsigned short hblank_start; /* horizontal blank start */ + unsigned short hblank_end; /* horizontal blank end */ + unsigned short hsync_start; /* horizontal sync start */ + unsigned short hsync_end; /* horizontal sync end */ + unsigned short vtotal; /* vertical total */ + unsigned short vblank_start; /* vertical blank start */ + unsigned short vblank_end; /* vertical blank end */ + unsigned short vsync_start; /* vertical sync start */ + unsigned short vsync_end; /* vertical sync end */ +} mdfld_hdmi_timing_t; + + + // // SPD InfoFrame structure // @@ -911,6 +933,18 @@ struct hdmi_edid_info { char *edid_info; }; +/* + * Structure representing EDID CEA extention block + * See Table 56, Table 26 and section A.2.13 of CEA-861-C for details + */ +typedef struct { + unsigned char tag; + unsigned char revision; + unsigned char content_offset; + unsigned char flags; + unsigned char data[124]; +} extention_block_cea_t; + #define HDMI_EDID_INFO(nm, info) \ .monitor_name = nm, .edid_info = info diff --git a/drivers/staging/mrst/drv/psb_intel_reg.h b/drivers/staging/mrst/drv/psb_intel_reg.h index dca00f8..d572687 100644 --- a/drivers/staging/mrst/drv/psb_intel_reg.h +++ b/drivers/staging/mrst/drv/psb_intel_reg.h @@ -134,6 +134,12 @@ #define PFIT_AUTO_RATIOS 0x61238 +#define PFIT_FRACTIONAL_VALUE (1<<12) +#define PFIT_VERT_MSB_SHIFT 28 +#define PFIT_HORIZ_MSB_SHIFT 12 +#define PFIT_VERT_SCALE_SHIFT 16 +#define PFIT_HORIZ_SCALE_SHIFT 0 + #define DPLL_A 0x06014 #define DPLL_B 0x06018 diff --git a/drivers/staging/mrst/drv/psb_irq.c b/drivers/staging/mrst/drv/psb_irq.c index 33eec68..df9d2a8 100644 --- a/drivers/staging/mrst/drv/psb_irq.c +++ b/drivers/staging/mrst/drv/psb_irq.c @@ -101,6 +101,8 @@ psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) /* Enable the interrupt, clear any pending status */ if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_ONLY_IF_ON)) { u32 writeVal = PSB_RVDC32(reg); + /* Don't clear other interrupts */ + writeVal &= PIPE_EVENT_MASK; writeVal |= (mask | (mask >> 16)); PSB_WVDC32(writeVal, reg); (void) PSB_RVDC32(reg); @@ -117,6 +119,8 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) dev_priv->pipestat[pipe] &= ~mask; if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_ONLY_IF_ON)) { u32 writeVal = PSB_RVDC32(reg); + /* Don't clear other interrupts */ + writeVal &= PIPE_EVENT_MASK; writeVal &= ~mask; PSB_WVDC32(writeVal, reg); (void) PSB_RVDC32(reg); @@ -311,34 +315,42 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) struct drm_psb_private *dev_priv = (struct drm_psb_private *) dev->dev_private; - uint32_t pipe_stat_val = 0; + uint32_t pipe_stat_val; + uint32_t pipe_stat_val_raw; uint32_t pipe_stat_reg = psb_pipestat(pipe); - uint32_t pipe_enable = dev_priv->pipestat[pipe]; - uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16; + uint32_t pipe_enable; + uint32_t pipe_status; uint32_t i = 0; unsigned long irq_flags; spin_lock_irqsave(&dev_priv->irqmask_lock, irq_flags); + pipe_enable = dev_priv->pipestat[pipe]; + pipe_status = dev_priv->pipestat[pipe] >> 16; + pipe_stat_val = PSB_RVDC32(pipe_stat_reg); + pipe_stat_val_raw = pipe_stat_val; pipe_stat_val &= pipe_enable | pipe_status; pipe_stat_val &= pipe_stat_val >> 16; - spin_unlock_irqrestore(&dev_priv->irqmask_lock, irq_flags); - - /* clear the 2nd level interrupt status bits */ + /* clear the 2nd level interrupt status bits. + * We must keep spinlock to protect disable / enable status + * safe in the same register (assuming that other do that also) + * Clear only bits that we are going to serve this time. + */ /** * FIXME: shouldn't use while loop here. However, the interrupt * status 'sticky' bits cannot be cleared by setting '1' to that * bit once... */ for (i = 0; i < WAIT_STATUS_CLEAR_LOOP_COUNT; i ++) { - PSB_WVDC32(PSB_RVDC32(pipe_stat_reg), pipe_stat_reg); + PSB_WVDC32(pipe_stat_val_raw, pipe_stat_reg); (void) PSB_RVDC32(pipe_stat_reg); - if ((PSB_RVDC32(pipe_stat_reg) & pipe_status) == 0) + if ((PSB_RVDC32(pipe_stat_reg) & pipe_stat_val) == 0) break; } + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irq_flags); if (i == WAIT_STATUS_CLEAR_LOOP_COUNT) DRM_ERROR("%s, can't clear the status bits in pipe_stat_reg, its value = 0x%x. \n", diff --git a/drivers/staging/mrst/drv/psb_powermgmt.c b/drivers/staging/mrst/drv/psb_powermgmt.c index 184f57b..5594334 100644 --- a/drivers/staging/mrst/drv/psb_powermgmt.c +++ b/drivers/staging/mrst/drv/psb_powermgmt.c @@ -62,6 +62,15 @@ extern u32 DISP_PLANEB_STATUS; static bool gbSuspended = false; bool gbgfxsuspended = false; +void acquire_ospm_lock(void) +{ + mutex_lock(&g_ospm_mutex); +} + +void release_ospm_lock(void) +{ + mutex_unlock(&g_ospm_mutex); +} /* * gfx_early_suspend * @@ -70,7 +79,7 @@ static void gfx_early_suspend(struct early_suspend *h); static void gfx_late_resume(struct early_suspend *h); static struct early_suspend gfx_early_suspend_desc = { - .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB, .suspend = gfx_early_suspend, .resume = gfx_late_resume, }; @@ -1475,6 +1484,23 @@ void ospm_suspend_display(struct drm_device *dev) } /* + * is_hdmi_plugged_out + * + * Description: to check whether hdmi is plugged out in S3 suspend + * + */ +static bool is_hdmi_plugged_out(void) +{ + u8 data = 0; + intel_scu_ipc_ioread8(MSIC_HDMI_STATUS, &data); + + if ((data & HPD_SIGNAL_STATUS)) { + return false; + } else { + return true; + } +} +/* * ospm_resume_display * * Description: Resume the display hardware restoring state and enabling @@ -1532,15 +1558,24 @@ void ospm_resume_display(struct pci_dev *pdev) * Don't restore Display B registers during resuming, if HDMI * isn't turned on before suspending. */ - if ((dev_priv->panel_desc & DISPLAY_B) && - (dev_priv->saveHDMIB_CONTROL & HDMIB_PORT_EN)) { + if (dev_priv->panel_desc & DISPLAY_B) { mdfld_restore_display_registers(dev, 1); + /*devices connect status will be changed + when system suspend,re-detect once here*/ #ifdef CONFIG_SND_INTELMID_HDMI_AUDIO - if (dev_priv->had_pvt_data && hdmi_state) { - if (!dev_priv->had_interface->resume(dev_priv->had_pvt_data)) { - uevent_string = "HDMI_AUDIO_PM_RESUMED=1"; - psb_sysfs_uevent(dev_priv->dev, uevent_string); + if (!is_hdmi_plugged_out()) { + PSB_DEBUG_ENTRY("resume hdmi_state %d", hdmi_state); + if (dev_priv->had_pvt_data && hdmi_state) { + if (!dev_priv->had_interface->resume(dev_priv->had_pvt_data)) { + uevent_string = "HDMI_AUDIO_PM_RESUMED=1"; + psb_sysfs_uevent(dev_priv->dev, uevent_string); + } } + } else { + PSB_DEBUG_ENTRY("hdmi is unplugged: %d!\n", hdmi_state); + if (hdmi_state) + schedule_work(&dev_priv->hdmi_hotplug_wq); + msleep(100); } #endif } @@ -1683,7 +1718,8 @@ static void gfx_early_suspend(struct early_suspend *h) if( dev_priv->drm_psb_widi ) dev_priv->drm_psb_widi = 0; - + if (dev_priv->pvr_screen_event_handler) + dev_priv->pvr_screen_event_handler(dev, 0); /*Display off*/ if (IS_MDFLD(gpDrmDevice)) { if ((dev_priv->panel_id == TMD_VID) || @@ -1755,7 +1791,6 @@ static void gfx_late_resume(struct early_suspend *h) ospm_resume_display(gpDrmDevice->pdev); psb_irq_preinstall_islands(gpDrmDevice, OSPM_DISPLAY_ISLAND); psb_irq_postinstall_islands(gpDrmDevice, OSPM_DISPLAY_ISLAND); - #endif if (IS_MDFLD(gpDrmDevice)) { if ((dev_priv->panel_id == TMD_VID) || @@ -1804,7 +1839,8 @@ static void gfx_late_resume(struct early_suspend *h) 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; if (lastFailedBrightness > 0) @@ -1945,7 +1981,7 @@ void ospm_power_island_up(int hw_islands) If pmu_nc_set_power_state fails then accessing HW reg would result in a crash - IERR/Fabric error. */ - +#ifdef CONFIG_MDFD_GL3 if (IS_D0(gpDrmDevice)) { /* * GL3 power island needs to be on for MSVDX working. @@ -1956,7 +1992,7 @@ void ospm_power_island_up(int hw_islands) !ospm_power_is_hw_on(OSPM_GL3_CACHE_ISLAND)) gfx_islands |= OSPM_GL3_CACHE_ISLAND; } - +#endif spin_lock_irqsave(&dev_priv->ospm_lock, flags); if (pmu_nc_set_power_state(gfx_islands, OSPM_ISLAND_UP, APM_REG_TYPE)) @@ -2056,6 +2092,7 @@ void ospm_power_island_down(int hw_islands) #endif spin_lock_irqsave(&dev_priv->ospm_lock, flags); if (gfx_islands & OSPM_GL3_CACHE_ISLAND) { +#ifdef CONFIG_MDFD_GL3 /* Make sure both GFX & Video aren't using GL3 @@ -2075,6 +2112,7 @@ void ospm_power_island_down(int hw_islands) if (!gfx_islands) goto out; } +#endif } /* @@ -2158,7 +2196,6 @@ bool ospm_power_using_hw_begin(int hw_island, UHBUsage usage) goto increase_count; } } - if (!b_atomic) mutex_lock(&g_ospm_mutex); diff --git a/drivers/staging/mrst/drv/psb_powermgmt.h b/drivers/staging/mrst/drv/psb_powermgmt.h index 4327a06..0bcc193 100644 --- a/drivers/staging/mrst/drv/psb_powermgmt.h +++ b/drivers/staging/mrst/drv/psb_powermgmt.h @@ -124,6 +124,8 @@ int psb_runtime_resume(struct device *dev); int psb_runtime_idle(struct device *dev); int ospm_runtime_pm_allow(struct drm_device * dev); void ospm_runtime_pm_forbid(struct drm_device * dev); +void acquire_ospm_lock(void); +void release_ospm_lock(void); #endif /*_PSB_POWERMGMT_H_*/ diff --git a/drivers/staging/mrst/drv/tmd_6x10_vid.c b/drivers/staging/mrst/drv/tmd_6x10_vid.c index 5978a40..dc492e8 100755 --- a/drivers/staging/mrst/drv/tmd_6x10_vid.c +++ b/drivers/staging/mrst/drv/tmd_6x10_vid.c @@ -278,7 +278,7 @@ static int mdfld_dsi_pr2_power_on(struct mdfld_dsi_config *dsi_config) } /*Just turn on panel for WiDi Extended Mode.*/ - if (!dev_priv->drm_psb_widi) { + if (!dev_priv->drm_psb_widi && !dev_priv->dpms_on_off) { mdfld_dsi_send_gen_long_hs(sender, pr2_mcs_protect_off, 1, 0); /*change power state*/ mdfld_dsi_send_mcs_long_hs(sender, pr2_exit_sleep_mode, 1, 0); @@ -338,7 +338,7 @@ static int mdfld_dsi_pr2_power_off(struct mdfld_dsi_config *dsi_config) } /*Just turn off panel for WiDi Extended Mode.*/ - if (!dev_priv->drm_psb_widi) { + if (!dev_priv->drm_psb_widi && !dev_priv->dpms_on_off) { mdfld_dsi_send_gen_long_hs(sender, pr2_mcs_protect_off, 1, 0); /*change power state here*/ mdfld_dsi_send_mcs_long_hs(sender, pr2_set_display_off, 1, 0); diff --git a/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb.h b/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb.h index 4283234..0301e58 100755 --- a/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb.h +++ b/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb.h @@ -59,6 +59,7 @@ typedef enum tag_mrst_bool } MRST_BOOL, *MRST_PBOOL; typedef int(* MRSTLFB_VSYNC_ISR_PFN)(struct drm_device* psDrmDevice, int iPipe); +typedef int(* MRSTLFB_SCREEN_EVENT_PFN)(struct drm_device* psDrmDevice, int state); typedef struct MRSTLFB_BUFFER_TAG @@ -222,6 +223,7 @@ typedef struct MRSTLFB_DEVINFO_TAG MRST_BOOL bLastFlipAddrValid; + MRST_BOOL bScreenState; } MRSTLFB_DEVINFO; #if 0 diff --git a/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb_displayclass.c b/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb_displayclass.c index f6095c9..665ac06 100755 --- a/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb_displayclass.c +++ b/drivers/staging/mrst/pvr/services4/3rdparty/linux_framebuffer_drm/drmlfb_displayclass.c @@ -1460,6 +1460,33 @@ static int DRMLFBEnterVTHandler(struct drm_device *dev) return 0; } #endif +static +int MRSTLFBScreenEventHandler(struct drm_device* psDrmDevice, int state) +{ + MRSTLFB_DEVINFO *psDevInfo; + MRST_BOOL bScreenOFF; + + psDevInfo = GetAnchorPtr(); + + bScreenOFF = (state == 0) ? MRST_TRUE: MRST_FALSE; + + if (bScreenOFF != psDevInfo->bScreenState) + { + DRM_INFO("Screen event:%d\n", bScreenOFF); + psDevInfo->bScreenState = bScreenOFF; + SetFlushState(psDevInfo, bScreenOFF); + } + + return 0; +} + +static MRST_ERROR MRSTLFBInstallScreenEvents(MRSTLFB_DEVINFO *psDevInfo, MRSTLFB_SCREEN_EVENT_PFN pScreenEventHandler) +{ + struct drm_psb_private *dev_priv = + (struct drm_psb_private *) psDevInfo->psDrmDevice->dev_private; + dev_priv->pvr_screen_event_handler = pScreenEventHandler; + return (MRST_OK); +} static MRST_ERROR InitDev(MRSTLFB_DEVINFO *psDevInfo) { @@ -1705,7 +1732,7 @@ MRST_ERROR MRSTLFBInit(struct drm_device * dev) psDrmPriv->psb_leave_vt_handler = DRMLFBLeaveVTHandler; psDrmPriv->psb_enter_vt_handler = DRMLFBEnterVTHandler; #endif - + MRSTLFBInstallScreenEvents(psDevInfo, MRSTLFBScreenEventHandler); psDevInfo->ulRefCount++; diff --git a/drivers/staging/mrst/pvr/services4/srvkm/bridged/bridged_pvr_bridge.c b/drivers/staging/mrst/pvr/services4/srvkm/bridged/bridged_pvr_bridge.c index d65c989..8c6dac3 100755 --- a/drivers/staging/mrst/pvr/services4/srvkm/bridged/bridged_pvr_bridge.c +++ b/drivers/staging/mrst/pvr/services4/srvkm/bridged/bridged_pvr_bridge.c @@ -4882,7 +4882,6 @@ IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, goto return_fault; } - if(psBridgePackageKM->ui32InBufferSize > 0) { if(!OSAccessOK(PVR_VERIFY_READ, -- 2.7.4