[Intel-gfx] [PATCH 5/6] drm/i915/tc/icl: Implement TC cold sequences
José Roberto de Souza
jose.souza at intel.com
Wed Apr 1 00:41:19 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.
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>
---
Will run some tests in the office with TBT dockstation to check if
it will be a issue keep both aux enabled. Otherwise more changes will
be required here.
.../drm/i915/display/intel_display_power.c | 12 ++++-
.../drm/i915/display/intel_display_types.h | 1 +
drivers/gpu/drm/i915/display/intel_tc.c | 47 ++++++++++++++++++-
drivers/gpu/drm/i915/display/intel_tc.h | 2 +
drivers/gpu/drm/i915/i915_reg.h | 1 +
5 files changed, 59 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 dbd61517ba63..1ccd57d645c7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -592,9 +592,17 @@ 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)
+ intel_tc_icl_tc_cold_exit(dev_priv);
- _hsw_power_well_continue_enable(dev_priv, power_well);
+ /*
+ * To avoid power well enable timeouts when disconnected or in TBT mode
+ * when doing the TC cold exit sequence for GEN11
+ */
+ if (INTEL_GEN(dev_priv) != 11 ||
+ (intel_tc_port_live_status_mask(dig_port) &
+ (TC_PORT_LEGACY | TC_PORT_DP_ALT)))
+ _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..b6d67f069ef7 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -7,6 +7,7 @@
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_dp_mst.h"
+#include "intel_sideband.h"
#include "intel_tc.h"
static const char *tc_port_mode_name(enum tc_port_mode mode)
@@ -506,6 +507,13 @@ static void __intel_tc_port_lock(struct intel_digital_port *dig_port,
mutex_lock(&dig_port->tc_lock);
+ if (INTEL_GEN(i915) == 11 && dig_port->tc_link_refcount == 0) {
+ enum intel_display_power_domain aux_domain;
+
+ aux_domain = intel_aux_ch_to_power_domain(dig_port->aux_ch);
+ dig_port->tc_cold_wakeref = intel_display_power_get(i915, aux_domain);
+ }
+
if (!dig_port->tc_link_refcount &&
intel_tc_port_needs_reset(dig_port))
intel_tc_port_reset_mode(dig_port, required_lanes);
@@ -519,15 +527,30 @@ void intel_tc_port_lock(struct intel_digital_port *dig_port)
__intel_tc_port_lock(dig_port, 1);
}
+static void icl_tc_cold_unblock(struct intel_digital_port *dig_port)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum intel_display_power_domain aux_domain;
+ intel_wakeref_t tc_cold_wakeref;
+
+ if (INTEL_GEN(i915) != 11 || dig_port->tc_link_refcount > 0)
+ return;
+
+ tc_cold_wakeref = fetch_and_zero(&dig_port->tc_cold_wakeref);
+ aux_domain = intel_aux_ch_to_power_domain(dig_port->aux_ch);
+ intel_display_power_put_async(i915, aux_domain, tc_cold_wakeref);
+}
+
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);
+ icl_tc_cold_unblock(dig_port);
+
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 +571,7 @@ void intel_tc_port_put_link(struct intel_digital_port *dig_port)
{
mutex_lock(&dig_port->tc_lock);
dig_port->tc_link_refcount--;
+ icl_tc_cold_unblock(dig_port);
mutex_unlock(&dig_port->tc_lock);
}
@@ -568,3 +592,22 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
dig_port->tc_link_refcount = 0;
tc_port_load_fia_params(i915, dig_port);
}
+
+void intel_tc_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);
+
+ if (!ret)
+ msleep(1);
+
+ if (ret)
+ drm_dbg_kms(&i915->drm, "TC cold block %s\n",
+ (ret == 0 ? "succeeded" : "failed"));
+}
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index a1afcee48818..168d8896fcfd 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);
@@ -29,5 +30,6 @@ bool intel_tc_port_ref_held(struct intel_digital_port *dig_port);
void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy);
u32 intel_tc_port_live_status_mask(struct intel_digital_port *dig_port);
+void intel_tc_icl_tc_cold_exit(struct drm_i915_private *i915);
#endif /* __INTEL_TC_H__ */
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
mailing list