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:
Algea Cao
2024-10-31 11:24:28 +08:00
committed by Tao Huang
parent 9367bc29e5
commit 122ffa74f5
3 changed files with 60 additions and 0 deletions

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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,