Commit 9488a030 authored by Swati Sharma's avatar Swati Sharma Committed by Jani Nikula

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: default avatarSwati Sharma <swati2.sharma@intel.com>
Signed-off-by: default avatarAnkit Nautiyal <ankit.k.nautiyal@intel.com>
Reviewed-by: Uma Shankar <uma.shankar@intel.com> (v2)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201218103723.30844-12-ankit.k.nautiyal@intel.com
parent 4f3dd47a
...@@ -6001,6 +6001,28 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) ...@@ -6001,6 +6001,28 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
return link_ok; 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 static bool
intel_dp_needs_link_retrain(struct intel_dp *intel_dp) intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
{ {
...@@ -6366,7 +6388,7 @@ intel_dp_hotplug(struct intel_encoder *encoder, ...@@ -6366,7 +6388,7 @@ intel_dp_hotplug(struct intel_encoder *encoder,
return state; 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); struct drm_i915_private *i915 = dp_to_i915(intel_dp);
u8 val; u8 val;
...@@ -6390,6 +6412,30 @@ static void intel_dp_check_service_irq(struct intel_dp *intel_dp) ...@@ -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"); 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 * According to DP spec
* 5.1.2: * 5.1.2:
...@@ -6429,7 +6475,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) ...@@ -6429,7 +6475,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
return false; 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 */ /* Handle CEC interrupts, if any */
drm_dp_cec_irq(&intel_dp->aux); drm_dp_cec_irq(&intel_dp->aux);
...@@ -6859,7 +6906,7 @@ intel_dp_detect(struct drm_connector *connector, ...@@ -6859,7 +6906,7 @@ intel_dp_detect(struct drm_connector *connector,
to_intel_connector(connector)->detect_edid) to_intel_connector(connector)->detect_edid)
status = connector_status_connected; status = connector_status_connected;
intel_dp_check_service_irq(intel_dp); intel_dp_check_device_service_irq(intel_dp);
out: out:
if (status != connector_status_connected && !intel_dp->is_mst) if (status != connector_status_connected && !intel_dp->is_mst)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment