All of lore.kernel.org
 help / color / mirror / Atom feed
From: Imre Deak <imre.deak@intel.com>
To: intel-gfx@lists.freedesktop.org
Cc: "José Roberto de Souza" <jose.souza@intel.com>
Subject: [Intel-gfx] [PATCH 11/13] drm/i915/tc: Fix TypeC PHY connect/disconnect logic on ADL-P
Date: Tue, 21 Sep 2021 03:23:11 +0300	[thread overview]
Message-ID: <20210921002313.1132357-12-imre.deak@intel.com> (raw)
In-Reply-To: <20210921002313.1132357-1-imre.deak@intel.com>

So far TC-cold was blocked only for the duration of TypeC mode resets.
The DP-alt and legacy modes require TC-cold to be blocked also whenever
the port is in use (AUX transfers, enable modeset), and this was ensured
by the held PHY ownership flag. On ADL-P this doesn't work, since the
PHY ownership flag is in a register backed by the PW#2 power well.
Whenever this power well is disabled the ownership flag is cleared by
the HW under the driver.

The only way to cleanly release and re-acquire the PHY ownership flag
and also allow for power saving (by disabling the display power wells
and reaching DC5/6 states) is to hold the TC-cold blocking power domains
while the PHY is connected and disconnect/reconnect the PHY on-demand
around AUX transfers and modeset enable/disables. Let's do that,
disconnecting a PHY with a 1 sec delay after it becomes idle. For
consistency do this on all platforms and TypeC modes.

Cc: José Roberto de Souza <jose.souza@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c      |  7 +-
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_tc.c       | 87 +++++++++++--------
 drivers/gpu/drm/i915/display/intel_tc.h       |  2 +-
 4 files changed, 60 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index b9194d6a4dfe7..b509d5f2d5f0e 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4019,8 +4019,11 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
 {
 	struct drm_i915_private *i915 = to_i915(encoder->dev);
 	struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
 
 	intel_dp_encoder_flush_work(encoder);
+	if (intel_phy_is_tc(i915, phy))
+		intel_tc_port_flush_work(dig_port);
 	intel_display_power_flush_work(i915);
 
 	drm_encoder_cleanup(encoder);
@@ -4445,7 +4448,7 @@ static void intel_ddi_encoder_suspend(struct intel_encoder *encoder)
 	if (!intel_phy_is_tc(i915, phy))
 		return;
 
-	intel_tc_port_disconnect_phy(dig_port);
+	intel_tc_port_flush_work(dig_port);
 }
 
 static void intel_ddi_encoder_shutdown(struct intel_encoder *encoder)
@@ -4460,7 +4463,7 @@ static void intel_ddi_encoder_shutdown(struct intel_encoder *encoder)
 	if (!intel_phy_is_tc(i915, phy))
 		return;
 
-	intel_tc_port_disconnect_phy(dig_port);
+	intel_tc_port_flush_work(dig_port);
 }
 
 #define port_tc_name(port) ((port) - PORT_TC1 + '1')
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 08a73ffded957..53509f6ae3d10 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1667,6 +1667,7 @@ struct intel_digital_port {
 	struct mutex tc_lock;	/* protects the TypeC port mode */
 	intel_wakeref_t tc_lock_wakeref;
 	enum intel_display_power_domain tc_lock_power_domain;
+	struct delayed_work tc_disconnect_phy_work;
 	int tc_link_refcount;
 	bool tc_legacy_port:1;
 	char tc_port_name[8];
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 8d799cf7ccefd..3fefd00e04685 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -645,6 +645,13 @@ static void intel_tc_port_update_mode(struct intel_digital_port *dig_port,
 
 	intel_tc_port_reset_mode(dig_port, required_lanes, force_disconnect);
 
+	/* Get power domain matching the new mode after reset. */
+	tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain,
+			fetch_and_zero(&dig_port->tc_lock_wakeref));
+	if (dig_port->tc_mode != TC_PORT_DISCONNECTED)
+		dig_port->tc_lock_wakeref = tc_cold_block(dig_port,
+							  &dig_port->tc_lock_power_domain);
+
 	tc_cold_unblock(dig_port, domain, wref);
 }
 
@@ -672,6 +679,7 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 		active_links = to_intel_crtc(encoder->base.crtc)->active;
 
 	drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED);
+	drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
 	if (active_links) {
 		enum intel_display_power_domain domain;
 		intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port, &domain);
@@ -684,6 +692,9 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 				    dig_port->tc_port_name, active_links);
 		intel_tc_port_link_init_refcount(dig_port, active_links);
 
+		dig_port->tc_lock_wakeref = tc_cold_block(dig_port,
+							  &dig_port->tc_lock_power_domain);
+
 		tc_cold_unblock(dig_port, domain, tc_cold_wref);
 	}
 
@@ -724,60 +735,67 @@ bool intel_tc_port_connected(struct intel_encoder *encoder)
 }
 
 static void __intel_tc_port_lock(struct intel_digital_port *dig_port,
-				 int required_lanes, bool force_disconnect)
+				 int required_lanes)
 {
 	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	intel_wakeref_t wakeref;
-
-	wakeref = intel_display_power_get(i915, POWER_DOMAIN_DISPLAY_CORE);
 
 	mutex_lock(&dig_port->tc_lock);
 
+	cancel_delayed_work(&dig_port->tc_disconnect_phy_work);
 
 	if (!dig_port->tc_link_refcount)
 		intel_tc_port_update_mode(dig_port, required_lanes,
-					  force_disconnect);
+					  false);
 
 	drm_WARN_ON(&i915->drm, dig_port->tc_mode == TC_PORT_DISCONNECTED);
 	drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_TBT_ALT &&
 				!tc_phy_is_owned(dig_port));
-
-	drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
-	dig_port->tc_lock_wakeref = wakeref;
 }
 
 void intel_tc_port_lock(struct intel_digital_port *dig_port)
 {
-	__intel_tc_port_lock(dig_port, 1, false);
-}
-
-void intel_tc_port_unlock(struct intel_digital_port *dig_port)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	intel_wakeref_t wakeref = fetch_and_zero(&dig_port->tc_lock_wakeref);
-
-	mutex_unlock(&dig_port->tc_lock);
-
-	intel_display_power_put_async(i915, POWER_DOMAIN_DISPLAY_CORE,
-				      wakeref);
+	__intel_tc_port_lock(dig_port, 1);
 }
 
 /**
- * intel_tc_port_disconnect_phy: disconnect TypeC PHY from display port
+ * intel_tc_port_disconnect_phy_work: disconnect TypeC PHY from display port
  * @dig_port: digital port
  *
  * Disconnect the given digital port from its TypeC PHY (handing back the
- * control of the PHY to the TypeC subsystem). The only purpose of this
- * function is to force the disconnect even with a TypeC display output still
- * plugged to the TypeC connector, which is required by the TypeC firmwares
- * during system suspend and shutdown. Otherwise - during the unplug event
- * handling - the PHY ownership is released automatically by
- * intel_tc_port_reset_mode(), when calling this function is not required.
+ * control of the PHY to the TypeC subsystem). This will happen in a delayed
+ * manner after each aux transactions and modeset disables.
  */
-void intel_tc_port_disconnect_phy(struct intel_digital_port *dig_port)
+static void intel_tc_port_disconnect_phy_work(struct work_struct *work)
 {
-	__intel_tc_port_lock(dig_port, 1, true);
-	intel_tc_port_unlock(dig_port);
+	struct intel_digital_port *dig_port =
+		container_of(work, struct intel_digital_port, tc_disconnect_phy_work.work);
+
+	mutex_lock(&dig_port->tc_lock);
+
+	if (!dig_port->tc_link_refcount)
+		intel_tc_port_update_mode(dig_port, 1, true);
+
+	mutex_unlock(&dig_port->tc_lock);
+}
+
+/**
+ * intel_tc_port_flush_work: flush the work disconnecting the PHY
+ * @dig_port: digital port
+ *
+ * Flush the delayed work disconnecting an idle PHY.
+ */
+void intel_tc_port_flush_work(struct intel_digital_port *dig_port)
+{
+	flush_delayed_work(&dig_port->tc_disconnect_phy_work);
+}
+
+void intel_tc_port_unlock(struct intel_digital_port *dig_port)
+{
+	if (!dig_port->tc_link_refcount && dig_port->tc_mode != TC_PORT_DISCONNECTED)
+		queue_delayed_work(system_unbound_wq, &dig_port->tc_disconnect_phy_work,
+				   msecs_to_jiffies(1000));
+
+	mutex_unlock(&dig_port->tc_lock);
 }
 
 bool intel_tc_port_ref_held(struct intel_digital_port *dig_port)
@@ -789,16 +807,16 @@ bool intel_tc_port_ref_held(struct intel_digital_port *dig_port)
 void intel_tc_port_get_link(struct intel_digital_port *dig_port,
 			    int required_lanes)
 {
-	__intel_tc_port_lock(dig_port, required_lanes, false);
+	__intel_tc_port_lock(dig_port, required_lanes);
 	dig_port->tc_link_refcount++;
 	intel_tc_port_unlock(dig_port);
 }
 
 void intel_tc_port_put_link(struct intel_digital_port *dig_port)
 {
-	mutex_lock(&dig_port->tc_lock);
-	dig_port->tc_link_refcount--;
-	mutex_unlock(&dig_port->tc_lock);
+	intel_tc_port_lock(dig_port);
+	--dig_port->tc_link_refcount;
+	intel_tc_port_unlock(dig_port);
 }
 
 static bool
@@ -854,6 +872,7 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
 		 "%c/TC#%d", port_name(port), tc_port + 1);
 
 	mutex_init(&dig_port->tc_lock);
+	INIT_DELAYED_WORK(&dig_port->tc_disconnect_phy_work, intel_tc_port_disconnect_phy_work);
 	dig_port->tc_legacy_port = is_legacy;
 	dig_port->tc_mode = TC_PORT_DISCONNECTED;
 	dig_port->tc_link_refcount = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index 0fdcddb4fc870..6b47b29f551c9 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.h
+++ b/drivers/gpu/drm/i915/display/intel_tc.h
@@ -17,7 +17,6 @@ bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port);
 bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port);
 
 bool intel_tc_port_connected(struct intel_encoder *encoder);
-void intel_tc_port_disconnect_phy(struct intel_digital_port *dig_port);
 
 u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port);
 u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port);
@@ -28,6 +27,7 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
 void intel_tc_port_sanitize(struct intel_digital_port *dig_port);
 void intel_tc_port_lock(struct intel_digital_port *dig_port);
 void intel_tc_port_unlock(struct intel_digital_port *dig_port);
+void intel_tc_port_flush_work(struct intel_digital_port *dig_port);
 void intel_tc_port_get_link(struct intel_digital_port *dig_port,
 			    int required_lanes);
 void intel_tc_port_put_link(struct intel_digital_port *dig_port);
-- 
2.27.0


  parent reply	other threads:[~2021-09-21  0:23 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-21  0:23 [Intel-gfx] [PATCH 00/13] drm/i915/tc: Fix TypeC connect/disconnect sequences Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 01/13] drm/i915/tc: Fix TypeC port init/resume time sanitization Imre Deak
2021-09-23 23:10   ` Souza, Jose
2021-09-24 10:59     ` Jani Nikula
2021-09-24 11:06       ` Imre Deak
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-29 19:19     ` Souza, Jose
2021-09-21  0:23 ` [Intel-gfx] [PATCH 02/13] drm/i915/adlp/tc: Fix PHY connected check for Thunderbolt mode Imre Deak
2021-09-23 23:18   ` Souza, Jose
2021-09-24 15:24     ` Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 03/13] drm/i915/tc: Remove waiting for PHY complete during releasing ownership Imre Deak
2021-09-24  0:17   ` Souza, Jose
2021-09-21  0:23 ` [Intel-gfx] [PATCH 04/13] drm/i915/tc: Check for DP-alt, legacy sinks before taking PHY ownership Imre Deak
2021-09-24  0:30   ` Souza, Jose
2021-09-24 15:31     ` Imre Deak
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 05/13] drm/i915/tc: Add/use helpers to retrieve TypeC port properties Imre Deak
2021-09-24 19:54   ` Souza, Jose
2021-09-21  0:23 ` [Intel-gfx] [PATCH 06/13] drm/i915/tc: Don't keep legacy TypeC ports in connected state w/o a sink Imre Deak
2021-09-24 19:57   ` Souza, Jose
2021-09-21  0:23 ` [Intel-gfx] [PATCH 07/13] drm/i915/tc: Add a mode for the TypeC PHY's disconnected state Imre Deak
2021-09-27 21:16   ` Souza, Jose
2021-09-27 21:46     ` Imre Deak
2021-09-28 19:18       ` Souza, Jose
2021-09-28 19:34         ` Imre Deak
2021-09-28 19:45           ` Souza, Jose
2021-09-28 19:55             ` Imre Deak
2021-09-28 20:02               ` Souza, Jose
2021-09-28 20:08                 ` Imre Deak
2021-09-28 20:29                   ` Souza, Jose
2021-09-28 20:38                     ` Imre Deak
2021-09-28 20:56                       ` Souza, Jose
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 08/13] drm/i915/tc: Refactor TC-cold block/unblock helpers Imre Deak
2021-09-27 21:56   ` Souza, Jose
2021-09-27 22:13     ` Imre Deak
2021-09-27 22:21       ` Souza, Jose
2021-09-27 22:28         ` Imre Deak
2021-09-27 23:33           ` Souza, Jose
2021-09-27 23:51             ` Imre Deak
2021-09-28  0:14               ` Souza, Jose
2021-09-28  0:45                 ` Imre Deak
2021-09-28  1:03                   ` Souza, Jose
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 09/13] drm/i915/tc: Avoid using legacy AUX PW in TBT mode Imre Deak
2021-09-28 20:31   ` Souza, Jose
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 10/13] drm/i915/icl/tc: Remove the ICL special casing during TC-cold blocking Imre Deak
2021-09-27 22:02   ` Souza, Jose
2021-09-28 10:52     ` Imre Deak
2021-09-28 20:50       ` Souza, Jose
2021-09-21  0:23 ` Imre Deak [this message]
2021-09-28 20:51   ` [Intel-gfx] [PATCH 11/13] drm/i915/tc: Fix TypeC PHY connect/disconnect logic on ADL-P Souza, Jose
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:23 ` [Intel-gfx] [PATCH 12/13] drm/i915/tc: Drop extra TC cold blocking from intel_tc_port_connected() Imre Deak
2021-09-28 20:51   ` Souza, Jose
2021-09-21  0:23 ` [Intel-gfx] [PATCH 13/13] drm/i915/tc: Fix system hang on ADL-P during TypeC PHY disconnect Imre Deak
2021-09-28 20:55   ` Souza, Jose
2021-09-29 13:28   ` [Intel-gfx] [PATCH v2 " Imre Deak
2021-09-21  0:30 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915/tc: Fix TypeC connect/disconnect sequences Patchwork
2021-09-21  0:32 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-09-21  1:01 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-09-21  3:01 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
2021-09-29 13:42 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915/tc: Fix TypeC connect/disconnect sequences (rev8) Patchwork
2021-09-29 13:43 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-09-29 14:11 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-09-29 16:58 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
2021-09-29 21:16   ` Imre Deak
2021-09-29 22:23     ` Vudum, Lakshminarayana
2021-09-29 21:47 ` Patchwork
2021-09-29 21:54 ` Patchwork
2021-09-29 22:21 ` [Intel-gfx] ✓ Fi.CI.IGT: success " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210921002313.1132357-12-imre.deak@intel.com \
    --to=imre.deak@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jose.souza@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.