mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
drm/bridge: synopsys: dw-hdmi-qp: Keep display state if userspace doesn't disable display pipeline after hdmi plug out.
However, the hdmi 2.0 spec requires that some flags are set in the sink scdc regs, and those flags are very likely to be reset when the cable has been disconnected. This will thus result in a blank display, even if the display pipeline configuration hasn't been modified or is in the exact same state. The solution we've had so far is to enable the scrambling and high ratio related bits again on reconnection, but the hdmi 2.0 spec (Section 6.1.3.1 - Scrambling Control) requires that the scdc bit is set before sending any scrambled video signal. Using that solution thus breaks that expectation. So we need disable hdmi signal output when hdmi plug out. writing scdc scrambling and high ratio regs when hdmi plug in then enable hdmi signal output finally. Change-Id: I422455e1d5b60c3fd4a3ef35ccb46de9fb0f28f8 Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
@@ -2885,6 +2885,64 @@ void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi, bool enable)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_allm_enable);
|
||||
|
||||
/*
|
||||
* If userspace don't disable hdmi output when hdmi plug out,
|
||||
* turn off hdmi signal output. Recovering hdmi status that
|
||||
* before plug out via turn on hdmi signal output and do scdc
|
||||
* communication when hdmi plug in.
|
||||
*/
|
||||
void dw_hdmi_qp_handle_hpd(struct dw_hdmi_qp *hdmi, bool enable)
|
||||
{
|
||||
bool is_hdmi14 = false;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
/* hdmi2.1 don't support keep vop output in current version */
|
||||
if (hdmi->hdmi_data.video_mode.mtmdsclock > 600000000)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&hdmi->audio_mutex);
|
||||
if (!hdmi->dclk_en)
|
||||
goto err_dclk;
|
||||
|
||||
if (!enable && !hdmi->disabled) {
|
||||
hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0);
|
||||
hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN);
|
||||
msleep(50);
|
||||
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
|
||||
hdmi->disabled = true;
|
||||
goto err_dclk;
|
||||
}
|
||||
|
||||
if (hdmi->hdmi_data.video_mode.mtmdsclock <= 340000000)
|
||||
is_hdmi14 = true;
|
||||
|
||||
if (enable && hdmi->disabled) {
|
||||
if (!is_hdmi14) {
|
||||
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
|
||||
drm_scdc_set_scrambling(hdmi->ddc, 1);
|
||||
hdmi_writel(hdmi, 1, SCRAMB_CONFIG0);
|
||||
/* Wait for resuming transmission of TMDS clock and data */
|
||||
msleep(100);
|
||||
} else {
|
||||
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
|
||||
drm_scdc_set_scrambling(hdmi->ddc, 0);
|
||||
hdmi_writel(hdmi, 0, SCRAMB_CONFIG0);
|
||||
}
|
||||
|
||||
hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);
|
||||
hdmi->disabled = false;
|
||||
msleep(50);
|
||||
hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0);
|
||||
hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN);
|
||||
}
|
||||
|
||||
err_dclk:
|
||||
mutex_unlock(&hdmi->audio_mutex);
|
||||
out:
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_handle_hpd);
|
||||
|
||||
static int
|
||||
dw_hdmi_atomic_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_connector_state *state,
|
||||
|
||||
@@ -1459,6 +1459,7 @@ static void repo_hpd_event(struct work_struct *p_work)
|
||||
change = drm_helper_hpd_irq_event(hdmi->drm_dev);
|
||||
if (change) {
|
||||
dev_dbg(hdmi->dev, "hpd stat changed:%d\n", hdmi->hpd_stat);
|
||||
dw_hdmi_qp_handle_hpd(hdmi->hdmi_qp, hdmi->hpd_stat);
|
||||
dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, hdmi->hpd_stat, change);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,6 +353,7 @@ bool dw_hdmi_get_output_whether_hdmi(struct dw_hdmi *hdmi);
|
||||
int dw_hdmi_get_output_type_cap(struct dw_hdmi *hdmi);
|
||||
void dw_hdmi_set_cec_adap(struct dw_hdmi *hdmi, struct cec_adapter *adap);
|
||||
void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi_qp, bool enable);
|
||||
void dw_hdmi_qp_handle_hpd(struct dw_hdmi_qp *hdmi, bool enable);
|
||||
|
||||
void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi);
|
||||
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
||||
|
||||
Reference in New Issue
Block a user