forked from Minki/linux
drm/i915: Add support for enabling link status and recovery
In this patch enables support for detecting link failures between PCON and HDMI sink in i915 driver. HDMI link loss indication to upstream DP source is indicated via IRQ_HPD. This is followed by reading of HDMI link configuration status (HDMI_TX_LINK_ACTIVE_STATUS). If the PCON → HDMI 2.1 link status is off; reinitiate frl link training to recover. Also, report HDMI FRL link error count range for each individual FRL active lane is indicated by DOWNSTREAM_HDMI_ERROR_STATUS_LN registers. v2: Checked for dpcd read and write failures and added debug message. (Uma Shankar) v3: Rearranged code to re-start FRL link training or fall back to TMDS mode. v4: Resused function to check frl which inturn restarts FRL and fallback to TMDS mode. Signed-off-by: Swati Sharma <swati2.sharma@intel.com> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> Reviewed-by: Uma Shankar <uma.shankar@intel.com> (v2) Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20201218103723.30844-12-ankit.k.nautiyal@intel.com
This commit is contained in:
parent
4f3dd47acb
commit
9488a030ac
@ -6001,6 +6001,28 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
return link_ok;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp)
|
||||
{
|
||||
bool is_active;
|
||||
u8 buf = 0;
|
||||
|
||||
is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux);
|
||||
if (intel_dp->frl.is_trained && !is_active) {
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf) < 0)
|
||||
return;
|
||||
|
||||
buf &= ~DP_PCON_ENABLE_HDMI_LINK;
|
||||
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf) < 0)
|
||||
return;
|
||||
|
||||
drm_dp_pcon_hdmi_frl_link_error_count(&intel_dp->aux, &intel_dp->attached_connector->base);
|
||||
|
||||
/* Restart FRL training or fall back to TMDS mode */
|
||||
intel_dp_check_frl_training(intel_dp);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
|
||||
{
|
||||
@ -6366,7 +6388,7 @@ intel_dp_hotplug(struct intel_encoder *encoder,
|
||||
return state;
|
||||
}
|
||||
|
||||
static void intel_dp_check_service_irq(struct intel_dp *intel_dp)
|
||||
static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
u8 val;
|
||||
@ -6390,6 +6412,30 @@ static void intel_dp_check_service_irq(struct intel_dp *intel_dp)
|
||||
drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n");
|
||||
}
|
||||
|
||||
static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
u8 val;
|
||||
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
|
||||
return;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux,
|
||||
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val) {
|
||||
drm_dbg_kms(&i915->drm, "Error in reading link service irq vector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (drm_dp_dpcd_writeb(&intel_dp->aux,
|
||||
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) {
|
||||
drm_dbg_kms(&i915->drm, "Error in writing link service irq vector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (val & HDMI_LINK_STATUS_CHANGED)
|
||||
intel_dp_handle_hdmi_link_status_change(intel_dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* According to DP spec
|
||||
* 5.1.2:
|
||||
@ -6429,7 +6475,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
|
||||
return false;
|
||||
}
|
||||
|
||||
intel_dp_check_service_irq(intel_dp);
|
||||
intel_dp_check_device_service_irq(intel_dp);
|
||||
intel_dp_check_link_service_irq(intel_dp);
|
||||
|
||||
/* Handle CEC interrupts, if any */
|
||||
drm_dp_cec_irq(&intel_dp->aux);
|
||||
@ -6859,7 +6906,7 @@ intel_dp_detect(struct drm_connector *connector,
|
||||
to_intel_connector(connector)->detect_edid)
|
||||
status = connector_status_connected;
|
||||
|
||||
intel_dp_check_service_irq(intel_dp);
|
||||
intel_dp_check_device_service_irq(intel_dp);
|
||||
|
||||
out:
|
||||
if (status != connector_status_connected && !intel_dp->is_mst)
|
||||
|
Loading…
Reference in New Issue
Block a user