summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAbhinav Kumar <abhinavk@codeaurora.org>2017-11-17 19:53:39 -0800
committerAbhinav Kumar <abhinavk@codeaurora.org>2017-11-20 22:04:55 -0800
commit95c0e89b3767e552a78974379cd150d56b5e5fcd (patch)
tree91fe15de79cb48b5353a1ef1f40738383b43acd2 /drivers
parent172ea1ed543aa9f35b39d1bb31754bcfe49bcfe9 (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.c6
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c72
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h3
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_ */