From 7c70884cd2b1b83bc904aacf0fd5caeee62f0b90 Mon Sep 17 00:00:00 2001
From: "Chia-Lin Kao (AceLan)" <acelan.kao@canonical.com>
Date: Mon, 2 Mar 2026 13:11:47 +0800
Subject: [PATCH 2/2] debug

Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_dp.c       | 34 +++++++++++++++++--
 drivers/usb/typec/class.c                     | 15 ++++++--
 drivers/usb/typec/ucsi/displayport.c          | 18 ++++++++++
 drivers/usb/typec/ucsi/ucsi.c                 |  7 ++++
 5 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 2b2abbc839130..8f6c507aab436 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1774,6 +1774,7 @@ struct intel_dp {
 
 	bool is_mst;
 	enum drm_dp_mst_mode mst_detect;
+	ktime_t last_short_hpd_time; /* debug: track rapid short HPD events */
 
 	/* connector directly attached - won't be use for modeset in mst world */
 	struct intel_connector *attached_connector;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 8e62456398899..a539606134fd4 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5113,6 +5113,7 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
 	struct intel_encoder *encoder = &dig_port->base;
 	bool link_ok = true;
 	bool reprobe_needed = false;
+	int loop_count = 0;
 
 	for (;;) {
 		u8 esi[4] = {};
@@ -5126,7 +5127,16 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
 			break;
 		}
 
-		drm_dbg_kms(display->drm, "DPRX ESI: %4ph\n", esi);
+		drm_dbg_kms(display->drm, "DPRX ESI: %4ph (loop=%d active_streams=%d)\n",
+			    esi, loop_count, intel_dp_mst_active_streams(intel_dp));
+		loop_count++;
+
+		if (loop_count > 8) {
+			drm_warn(display->drm,
+				 "[ENCODER:%d:%s] MST ESI loop exceeded 8 iterations, breaking (ESI=%4ph)\n",
+				 encoder->base.base.id, encoder->base.name, esi);
+			break;
+		}
 
 		if (intel_dp_mst_active_streams(intel_dp) > 0 && link_ok &&
 		    esi[3] & LINK_STATUS_CHANGED) {
@@ -5144,8 +5154,12 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
 			ack[3] |= DP_TUNNELING_IRQ;
 		}
 
-		if (mem_is_zero(ack, sizeof(ack)))
+		if (mem_is_zero(ack, sizeof(ack))) {
+			drm_dbg_kms(display->drm,
+				    "[ENCODER:%d:%s] MST ESI: no pending IRQs after %d iterations\n",
+				    encoder->base.base.id, encoder->base.name, loop_count);
 			break;
+		}
 
 		if (!intel_dp_ack_sink_irq_esi(intel_dp, ack))
 			drm_dbg_kms(display->drm, "Failed to ack ESI\n");
@@ -6351,6 +6365,22 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd)
 		    dig_port->base.base.name,
 		    long_hpd ? "long" : "short");
 
+	if (!long_hpd && intel_dp->is_mst) {
+		ktime_t now = ktime_get();
+		s64 delta_ms = ktime_ms_delta(now, intel_dp->last_short_hpd_time);
+
+		drm_dbg_kms(display->drm,
+			    "[ENCODER:%d:%s] MST short HPD: delta since last=%lldms\n",
+			    dig_port->base.base.base.id,
+			    dig_port->base.base.name, delta_ms);
+		if (delta_ms < 100)
+			drm_warn(display->drm,
+				 "[ENCODER:%d:%s] MST rapid HPD detected: %lldms since last pulse\n",
+				 dig_port->base.base.base.id,
+				 dig_port->base.base.name, delta_ms);
+		intel_dp->last_short_hpd_time = now;
+	}
+
 	/*
 	 * TBT DP tunnels require the GFX driver to read out the DPRX caps in
 	 * response to long HPD pulses. The DP hotplug handler does that,
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 67a533e351506..280ab56ecbc46 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -305,10 +305,21 @@ void typec_altmode_update_active(struct typec_altmode *adev, bool active)
 		return;
 
 	if (!is_typec_port(adev->dev.parent) && adev->dev.driver) {
-		if (!active)
+		if (!active) {
+			dev_dbg(&adev->dev,
+				"DEBUG: altmode %s deactivated, dropping module ref (driver=%s)\n",
+				dev_name(&adev->dev), adev->dev.driver->name);
 			module_put(adev->dev.driver->owner);
-		else
+		} else {
+			dev_dbg(&adev->dev,
+				"DEBUG: altmode %s activating, acquiring module ref (driver=%s)\n",
+				dev_name(&adev->dev), adev->dev.driver->name);
 			WARN_ON(!try_module_get(adev->dev.driver->owner));
+		}
+	} else if (!is_typec_port(adev->dev.parent) && !adev->dev.driver) {
+		dev_warn(&adev->dev,
+			 "DEBUG: altmode %s has no driver bound, skipping module ref (active=%d)\n",
+			 dev_name(&adev->dev), active);
 	}
 
 	adev->active = active;
diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c
index 8aae80b457d74..7079ec1996d62 100644
--- a/drivers/usb/typec/ucsi/displayport.c
+++ b/drivers/usb/typec/ucsi/displayport.c
@@ -54,6 +54,9 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo)
 	u8 cur = 0;
 	int ret;
 
+	dev_dbg(&alt->dev, "DEBUG: con%d ucsi_displayport_enter (initialized=%d override=%d)\n",
+		dp->con->num, dp->initialized, dp->override);
+
 	if (!ucsi_con_mutex_lock(dp->con))
 		return -ENOTCONN;
 
@@ -113,6 +116,9 @@ static int ucsi_displayport_exit(struct typec_altmode *alt)
 	u64 command;
 	int ret = 0;
 
+	dev_dbg(&alt->dev, "DEBUG: con%d ucsi_displayport_exit (initialized=%d override=%d)\n",
+		dp->con->num, dp->initialized, dp->override);
+
 	if (!ucsi_con_mutex_lock(dp->con))
 		return -ENOTCONN;
 
@@ -278,6 +284,10 @@ static void ucsi_displayport_work(struct work_struct *work)
 	struct ucsi_dp *dp = container_of(work, struct ucsi_dp, work);
 	int ret;
 
+	dev_dbg(&dp->alt->dev,
+		"DEBUG: con%d ucsi_displayport_work dispatching VDM header=0x%08x vdo_size=%d\n",
+		dp->con->num, dp->header, dp->vdo_size);
+
 	ret = typec_altmode_vdm(dp->alt, dp->header,
 				dp->vdo_data, dp->vdo_size);
 	if (ret)
@@ -299,8 +309,16 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt)
 	if (!dp)
 		return;
 
+	dev_dbg(&alt->dev,
+		"DEBUG: con%d ucsi_displayport_remove_partner enter (initialized=%d) - waiting for work\n",
+		dp->con->num, dp->initialized);
+
 	cancel_work_sync(&dp->work);
 
+	dev_dbg(&alt->dev,
+		"DEBUG: con%d ucsi_displayport_remove_partner work done, clearing state\n",
+		dp->con->num);
+
 	dp->data.conf = 0;
 	dp->data.status = 0;
 	dp->initialized = false;
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 2104af0e3af1e..044f1486b904b 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -861,6 +861,10 @@ static int ucsi_check_altmodes(struct ucsi_connector *con)
 {
 	int ret, num_partner_am;
 
+	dev_dbg(con->ucsi->dev,
+		"DEBUG: con%d ucsi_check_altmodes enter (partner=%p partner_altmode[0]=%p)\n",
+		con->num, con->partner, con->partner_altmode[0]);
+
 	ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
 	if (ret && ret != -ETIMEDOUT)
 		dev_err(con->ucsi->dev,
@@ -871,6 +875,9 @@ static int ucsi_check_altmodes(struct ucsi_connector *con)
 	if (con->partner_altmode[0]) {
 		num_partner_am = ucsi_get_num_altmode(con->partner_altmode);
 		typec_partner_set_num_altmodes(con->partner, num_partner_am);
+		dev_dbg(con->ucsi->dev,
+			"DEBUG: con%d calling ucsi_altmode_update_active (num_altmodes=%d)\n",
+			con->num, num_partner_am);
 		ucsi_altmode_update_active(con);
 		return 0;
 	} else {
-- 
2.51.0

