summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2026-02-25 19:46:13 +0300
committerImre Deak <imre.deak@intel.com>2026-03-03 18:49:08 +0300
commita4e50c53ccd81d91e435e1889f1b8291fac3580a (patch)
tree04472404541feba8026d7377d5465c2fb76a0787
parent7b05655171c217d61a95838cac19deb702b166b4 (diff)
downloadlinux-a4e50c53ccd81d91e435e1889f1b8291fac3580a.tar.xz
drm/i915/dp: Read/ack sink count and sink IRQs for SST as it's done for MST
Read and ack the sink count, sink device and link service IRQs for SST the same way this is done for MST, the read/ack happening in separate steps via an ESI (Event Status Indicator) vector. The above way is more efficient, since on newer (DPCD_REV >= 1.2) sinks the DP_SINK_COUNT_ESI..DP_LINK_SERVICE_IRQ_VECTOR_ESI0 registers can be read out in one AUX transaction - and the 3 last one written in one transaction. Also this allows sharing more of the SST and MST IRQ handling code (done as a follow-up). For now keep the current behavior of always reading the legacy DP_SINK_COUNT, DP_DEVICE_SERVICE_IRQ_VECTOR registers and not reading the DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 register. v2: Document the ESI vector get/ack helper fnuctions' return value. (Jani, Luca) Cc: Jani Nikula <jani.nikula@intel.com> Cc: Luca Coelho <luciano.coelho@intel.com> Reviewed-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Link: https://patch.msgid.link/20260225164618.1261368-16-imre.deak@intel.com
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c142
1 files changed, 79 insertions, 63 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index e2cbef2a41eb..4ca0c9cca65e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4965,6 +4965,76 @@ static bool intel_dp_ack_sink_irq_esi(struct intel_dp *intel_dp, u8 esi[4])
return false;
}
+/* Return %true if reading the ESI vector succeeded, %false otherwise. */
+static bool intel_dp_get_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
+{
+ memset(esi, 0, 4);
+
+ /*
+ * TODO: For DP_DPCD_REV >= 0x12 read
+ * DP_SINK_COUNT_ESI and DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0.
+ */
+ if (drm_dp_dpcd_read_data(&intel_dp->aux, DP_SINK_COUNT, esi, 2) != 0)
+ return false;
+
+ if (intel_dp->dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
+ return true;
+
+ /* TODO: Read DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 as well */
+ if (drm_dp_dpcd_read_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &esi[3]) != 0)
+ return false;
+
+ return true;
+}
+
+/* Return %true if acking the ESI vector IRQ events succeeded, %false otherwise. */
+static bool intel_dp_ack_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
+{
+ /*
+ * TODO: For DP_DPCD_REV >= 0x12 write
+ * DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0
+ */
+ if (drm_dp_dpcd_write_byte(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, esi[1]) != 0)
+ return false;
+
+ if (intel_dp->dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
+ return true;
+
+ /* TODO: Read DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 as well */
+ if (drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, esi[3]) != 0)
+ return false;
+
+ return true;
+}
+
+/*
+ * Return %true if reading the ESI vector and acking the ESI IRQ events succeeded,
+ * %false otherwise.
+ */
+static bool intel_dp_get_and_ack_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
+{
+ struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_connector *connector = intel_dp->attached_connector;
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+
+ if (!intel_dp_get_sink_irq_esi_sst(intel_dp, esi))
+ return false;
+
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s][ENCODER:%d:%s] DPRX ESI: %4ph\n",
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ esi);
+
+ if (mem_is_zero(&esi[1], 3))
+ return true;
+
+ if (!intel_dp_ack_sink_irq_esi_sst(intel_dp, esi))
+ return false;
+
+ return true;
+}
+
bool
intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
@@ -5785,31 +5855,6 @@ void intel_dp_check_link_state(struct intel_dp *intel_dp)
intel_encoder_link_check_queue_work(encoder, 0);
}
-/*
- * Return %true if a full connector reprobe is required due to a failure while
- * reading or acking the device service IRQs.
- */
-static bool intel_dp_get_and_ack_device_service_irq(struct intel_dp *intel_dp, u8 *irq_mask)
-{
- u8 val;
-
- *irq_mask = 0;
-
- if (drm_dp_dpcd_readb(&intel_dp->aux,
- DP_DEVICE_SERVICE_IRQ_VECTOR, &val) != 1)
- return false;
-
- if (!val)
- return true;
-
- if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, val) != 1)
- return false;
-
- *irq_mask = val;
-
- return true;
-}
-
static void intel_dp_handle_device_service_irq(struct intel_dp *intel_dp, u8 irq_mask)
{
struct intel_display *display = to_intel_display(intel_dp);
@@ -5824,31 +5869,6 @@ static void intel_dp_handle_device_service_irq(struct intel_dp *intel_dp, u8 irq
drm_dbg_kms(display->drm, "Sink specific irq unhandled\n");
}
-/* Return %true if reading and acking the link service IRQs succeeded. */
-static bool intel_dp_get_and_ack_link_service_irq(struct intel_dp *intel_dp, u8 *irq_mask)
-{
- u8 val;
-
- *irq_mask = 0;
-
- if (intel_dp->dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
- return true;
-
- if (drm_dp_dpcd_readb(&intel_dp->aux,
- DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1)
- return false;
-
- if (!val)
- return true;
-
- if (drm_dp_dpcd_writeb(&intel_dp->aux,
- DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1)
- return false;
-
- *irq_mask = val;
-
- return true;
-}
/*
* Return %true if a full connector reprobe is required after handling a link
@@ -5890,30 +5910,26 @@ static bool
intel_dp_short_pulse(struct intel_dp *intel_dp)
{
bool reprobe_needed = false;
- u8 irq_mask;
+ u8 esi[4] = {};
intel_dp_test_reset(intel_dp);
+ if (!intel_dp_get_and_ack_sink_irq_esi_sst(intel_dp, esi))
+ return false;
+
/*
- * Now read the DPCD to see if it's actually running
* If the current value of sink count doesn't match with
- * the value that was stored earlier or dpcd read failed
- * we need to do full detection
+ * the value that was stored earlier we need to do full
+ * detection.
*/
if (intel_dp_has_sink_count(intel_dp) &&
- drm_dp_read_sink_count(&intel_dp->aux) != intel_dp->sink_count)
+ DP_GET_SINK_COUNT(esi[0]) != intel_dp->sink_count)
/* No need to proceed if we are going to do full detect */
return false;
- if (!intel_dp_get_and_ack_device_service_irq(intel_dp, &irq_mask))
- return false;
-
- intel_dp_handle_device_service_irq(intel_dp, irq_mask);
-
- if (!intel_dp_get_and_ack_link_service_irq(intel_dp, &irq_mask))
- return false;
+ intel_dp_handle_device_service_irq(intel_dp, esi[1]);
- if (intel_dp_handle_link_service_irq(intel_dp, irq_mask))
+ if (intel_dp_handle_link_service_irq(intel_dp, esi[3]))
reprobe_needed = true;
/* Handle CEC interrupts, if any */