[PATCH 5/6] drm/i915/tc/icl: Implement TC cold sequences

José Roberto de Souza jose.souza at intel.com
Wed Apr 1 23:59:28 UTC 2020


This is required for legacy/static TC ports as IOM is not aware of
the connection and will not trigger the TC cold exit.

Just request PCODE to exit TCCOLD is not enough as it could enter
again be driver makes use of the port, to prevent it BSpec states that
aux powerwell should be held.

So here embedding the TC cold exit sequence into ICL aux enable,
it will enable aux, request tc cold exit and depending in the TC live
state continue with the regular aux enable sequence.

And then turning on aux power well during tc lock and turning off
during unlock both depending into the TC port refcount.

v2:
- moved ICL TC cold exit function to intel_display_power
- using dig_port->tc_legacy_port to only execute sequences for legacy
ports, hopefully VBTs will have this right
- fixed check to call _hsw_power_well_continue_enable()

BSpec: 21750
Fixes: https://gitlab.freedesktop.org/drm/intel/issues/1296
Cc: Imre Deak <imre.deak at intel.com>
Cc: Cooper Chiou <cooper.chiou at intel.com>
Cc: Kai-Heng Feng <kai.heng.feng at canonical.com>
Signed-off-by: José Roberto de Souza <jose.souza at intel.com>
---
 .../drm/i915/display/intel_display_power.c    | 27 ++++++++++++++--
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_tc.c       | 32 +++++++++++++++++--
 drivers/gpu/drm/i915/display/intel_tc.h       |  1 +
 drivers/gpu/drm/i915/i915_reg.h               |  1 +
 5 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 94f0d6d621d5..68f37445f9b9 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -575,6 +575,26 @@ static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv,
 
 #define TGL_AUX_PW_TO_TC_PORT(pw_idx)	((pw_idx) - TGL_PW_CTL_IDX_AUX_TC1)
 
+static void icl_tc_cold_exit(struct drm_i915_private *i915)
+{
+	int ret;
+
+	do {
+		ret = sandybridge_pcode_write_timeout(i915,
+						      ICL_PCODE_EXIT_TCCOLD,
+						      0, 250, 1);
+
+	} while (ret == -EAGAIN);
+
+	/* Spec states that TC cold exit can take up to 1ms to complete */
+	if (!ret)
+		msleep(1);
+
+	if (ret)
+		drm_dbg_kms(&i915->drm, "TC cold block %s\n",
+			    (ret == 0 ? "succeeded" : "failed"));
+}
+
 static void
 icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
 				 struct i915_power_well *power_well)
@@ -593,9 +613,12 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
 
 	_hsw_power_well_enable(dev_priv, power_well);
 
-	/* TODO ICL TC cold handling */
+	if (INTEL_GEN(dev_priv) == 11 && dig_port->tc_legacy_port)
+		icl_tc_cold_exit(dev_priv);
 
-	_hsw_power_well_continue_enable(dev_priv, power_well);
+	if (INTEL_GEN(dev_priv) != 11 || !dig_port->tc_legacy_port ||
+	    intel_tc_port_live_status_mask(dig_port))
+		_hsw_power_well_continue_enable(dev_priv, power_well);
 
 	if (INTEL_GEN(dev_priv) >= 12 && !power_well->desc->hsw.is_tc_tbt) {
 		enum tc_port tc_port;
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 176ab5f1e867..a9a4a3c1b4d7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1391,6 +1391,7 @@ struct intel_digital_port {
 	enum intel_display_power_domain ddi_io_power_domain;
 	struct mutex tc_lock;	/* protects the TypeC port mode */
 	intel_wakeref_t tc_lock_wakeref;
+	intel_wakeref_t tc_cold_wakeref;
 	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 d944be935423..c4dd551ff354 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -496,6 +496,30 @@ bool intel_tc_port_connected(struct intel_digital_port *dig_port)
 	return is_connected;
 }
 
+static void
+tc_cold_request(struct intel_digital_port *dig_port, bool block)
+{
+	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+	enum intel_display_power_domain domain;
+
+	if (dig_port->tc_link_refcount > 0 || INTEL_GEN(i915) != 11)
+		return;
+
+	if (!dig_port->tc_legacy_port)
+		return;
+
+	domain = intel_legacy_aux_to_power_domain(dig_port->aux_ch);
+
+	if (block) {
+		dig_port->tc_cold_wakeref = intel_display_power_get(i915,
+								    domain);
+	} else {
+		intel_display_power_put_async(i915, domain,
+					      dig_port->tc_cold_wakeref);
+		dig_port->tc_cold_wakeref = 0;
+	}
+}
+
 static void __intel_tc_port_lock(struct intel_digital_port *dig_port,
 				 int required_lanes)
 {
@@ -506,6 +530,8 @@ static void __intel_tc_port_lock(struct intel_digital_port *dig_port,
 
 	mutex_lock(&dig_port->tc_lock);
 
+	tc_cold_request(dig_port, true);
+
 	if (!dig_port->tc_link_refcount &&
 	    intel_tc_port_needs_reset(dig_port))
 		intel_tc_port_reset_mode(dig_port, required_lanes);
@@ -524,10 +550,11 @@ 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);
 
+	tc_cold_request(dig_port, false);
+
 	mutex_unlock(&dig_port->tc_lock);
 
-	intel_display_power_put_async(i915, POWER_DOMAIN_DISPLAY_CORE,
-				      wakeref);
+	intel_display_power_put_async(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref);
 }
 
 bool intel_tc_port_ref_held(struct intel_digital_port *dig_port)
@@ -548,6 +575,7 @@ void intel_tc_port_put_link(struct intel_digital_port *dig_port)
 {
 	mutex_lock(&dig_port->tc_lock);
 	dig_port->tc_link_refcount--;
+	tc_cold_request(dig_port, false);
 	mutex_unlock(&dig_port->tc_lock);
 }
 
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index a1afcee48818..19b653d63fe6 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.h
+++ b/drivers/gpu/drm/i915/display/intel_tc.h
@@ -9,6 +9,7 @@
 #include <linux/mutex.h>
 #include <linux/types.h>
 
+struct drm_i915_private;
 struct intel_digital_port;
 
 bool intel_tc_port_connected(struct intel_digital_port *dig_port);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 17484345cb80..b111815d6596 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -9107,6 +9107,7 @@ enum {
 #define     ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point)	(((point) << 16) | (0x1 << 8))
 #define   GEN6_PCODE_READ_D_COMP		0x10
 #define   GEN6_PCODE_WRITE_D_COMP		0x11
+#define   ICL_PCODE_EXIT_TCCOLD			0x12
 #define   HSW_PCODE_DE_WRITE_FREQ_REQ		0x17
 #define   DISPLAY_IPS_CONTROL			0x19
             /* See also IPS_CTL */
-- 
2.26.0



More information about the Intel-gfx-trybot mailing list