From: Imre Deak Date: Wed, 25 Feb 2026 16:46:13 +0000 (+0200) Subject: drm/i915/dp: Read/ack sink count and sink IRQs for SST as it's done for MST X-Git-Tag: v7.1-rc1~167^2~24^2~59 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a4e50c53ccd81d91e435e1889f1b8291fac3580a;p=thirdparty%2Flinux.git 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 Cc: Luca Coelho Reviewed-by: Luca Coelho Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260225164618.1261368-16-imre.deak@intel.com --- diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index e2cbef2a41eb0..4ca0c9cca65ec 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 */