Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95c0e89b authored by Abhinav Kumar's avatar Abhinav Kumar
Browse files

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: default avatarAbhinav Kumar <abhinavk@codeaurora.org>
parent 172ea1ed
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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,
+72 −0
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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_ */