diff options
author | Abhinav Kumar <abhinavk@codeaurora.org> | 2017-11-17 19:53:39 -0800 |
---|---|---|
committer | Abhinav Kumar <abhinavk@codeaurora.org> | 2017-11-20 22:04:55 -0800 |
commit | 95c0e89b3767e552a78974379cd150d56b5e5fcd (patch) | |
tree | 91fe15de79cb48b5353a1ef1f40738383b43acd2 /drivers | |
parent | 172ea1ed543aa9f35b39d1bb31754bcfe49bcfe9 (diff) |
drm/msm: implement HDMI teardown sequence for DRM driver
Currently the teardown sequence in the DRM HDMI driver is
incorrect and it places the HDMI controller in an incorrect
state during cable unplug OR device teardown.
Fix the teardown sequence and follow the hardware programming
sequence correctly to avoid artifacts.
Change-Id: Ifb9ec303fa710409087a74c03435c83823d02763
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h | 3 |
3 files changed, 81 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index b8aa29c13edf..5fbe4767ad3a 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -603,10 +603,16 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) if (phy) phy->funcs->powerdown(phy); + /* HDMI teardown sequence */ + sde_hdmi_ctrl_reset(hdmi); + if (hdmi->power_on) { _sde_hdmi_bridge_power_off(bridge); hdmi->power_on = false; } + + /* Powering-on the controller for HPD */ + sde_hdmi_ctrl_cfg(hdmi, 1); } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index a291a1112aeb..8ce90b9bc162 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -681,6 +681,78 @@ static void _sde_hdmi_scrambler_ddc_reset(struct hdmi *hdmi) hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val); } +void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on) +{ + uint32_t ctrl = 0; + unsigned long flags; + + spin_lock_irqsave(&hdmi->reg_lock, flags); + ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); + + if (power_on) + ctrl |= HDMI_CTRL_ENABLE; + else + ctrl &= ~HDMI_CTRL_ENABLE; + + hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); + spin_unlock_irqrestore(&hdmi->reg_lock, flags); + + HDMI_UTIL_DEBUG("HDMI Core: %s, HDMI_CTRL=0x%08x\n", + power_on ? "Enable" : "Disable", ctrl); +} + +static void sde_hdmi_clear_pkt_send(struct hdmi *hdmi) +{ + uint32_t reg_val; + + /* Clear audio sample send */ + reg_val = hdmi_read(hdmi, HDMI_AUDIO_PKT_CTRL); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_AUDIO_PKT_CTRL, reg_val); + + /* Clear sending VBI ctrl packets */ + reg_val = hdmi_read(hdmi, HDMI_VBI_PKT_CTRL); + reg_val &= ~(BIT(4) | BIT(8) | BIT(12)); + hdmi_write(hdmi, HDMI_VBI_PKT_CTRL, reg_val); + + /* Clear sending infoframe packets */ + reg_val = hdmi_read(hdmi, HDMI_INFOFRAME_CTRL0); + reg_val &= ~(BIT(0) | BIT(4) | BIT(8) | BIT(12) + | BIT(15) | BIT(19)); + hdmi_write(hdmi, HDMI_INFOFRAME_CTRL0, reg_val); + + /* Clear sending general ctrl packets */ + reg_val = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + reg_val &= ~(BIT(0) | BIT(4)); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, reg_val); +} + +void sde_hdmi_ctrl_reset(struct hdmi *hdmi) +{ + uint32_t reg_val; + + /* Assert HDMI CTRL SW reset */ + reg_val = hdmi_read(hdmi, HDMI_CTRL_SW_RESET); + reg_val |= BIT(0); + hdmi_write(hdmi, HDMI_CTRL_SW_RESET, reg_val); + + /* disable the controller and put to known state */ + sde_hdmi_ctrl_cfg(hdmi, 0); + + /* disable the audio engine */ + reg_val = hdmi_read(hdmi, HDMI_AUDIO_CFG); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_AUDIO_CFG, reg_val); + + /* clear sending packets to sink */ + sde_hdmi_clear_pkt_send(hdmi); + + /* De-assert HDMI CTRL SW reset */ + reg_val = hdmi_read(hdmi, HDMI_CTRL_SW_RESET); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_CTRL_SW_RESET, reg_val); +} + void _sde_hdmi_scrambler_ddc_disable(void *hdmi_display) { struct sde_hdmi *display = (struct sde_hdmi *)hdmi_display; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 3cef7e6aca39..340e665f2c28 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -198,4 +198,7 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); u8 sde_hdmi_hdr_get_ops(u8 curr_state, u8 new_state); +void sde_hdmi_ctrl_reset(struct hdmi *hdmi); +void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on); + #endif /* _SDE_HDMI_UTIL_H_ */ |