[v6,4/7] drm/i915/tgl: Add helper function for DC3CO exitline.

Submitted by Anshuamn Gupta on Sept. 3, 2019, 5:59 p.m.

Details

Message ID 20190903175939.6741-5-anshuman.gupta@intel.com
State New
Headers show
Series "DC3CO Support for TGL" ( rev: 6 ) in Intel GFX

Browsing this patch as part of:
"DC3CO Support for TGL" rev 6 in Intel GFX
<< prev patch [4/7] next patch >>

Commit Message

Anshuamn Gupta Sept. 3, 2019, 5:59 p.m.
DC3CO enabling B.Specs sequence requires to enable end configure
exit scanlines to TRANS_EXITLINE register, programming this register
has to be part of modeset sequence as this can't be change when
transcoder or port is enabled.
When system boots with only eDP panel there may not be real
modeset as BIOS has already programmed the necessary registers,
therefore it needs to force a modeset at bootup to enable and configure
DC3CO exitline.

Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c  |  5 +
 .../drm/i915/display/intel_display_power.c    | 95 +++++++++++++++++++
 .../drm/i915/display/intel_display_power.h    |  6 ++
 drivers/gpu/drm/i915/i915_drv.h               |  3 +
 drivers/gpu/drm/i915/intel_pm.c               |  2 +-
 drivers/gpu/drm/i915/intel_pm.h               |  2 +
 6 files changed, 112 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 12a94c6e3d51..01b23443c96b 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7409,6 +7409,8 @@  static int intel_crtc_compute_config(struct intel_crtc *crtc,
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	int clock_limit = dev_priv->max_dotclk_freq;
 
+	tgl_compute_dc3co_crtc(pipe_config);
+
 	if (INTEL_GEN(dev_priv) < 4) {
 		clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
 
@@ -13567,6 +13569,9 @@  static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta
 	if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true))
 		return;
 
+	if (!tgl_dc3co_can_enable_fastset(new_crtc_state))
+		return;
+
 	new_crtc_state->base.mode_changed = false;
 	new_crtc_state->update_pipe = true;
 
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 868197bb4860..95f352bf0173 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -19,6 +19,7 @@ 
 #include "intel_hotplug.h"
 #include "intel_sideband.h"
 #include "intel_tc.h"
+#include "intel_pm.h"
 
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 					 enum i915_power_well_id power_well_id);
@@ -772,6 +773,100 @@  static void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state)
 	dev_priv->csr.dc_state = val & mask;
 }
 
+void tgl_enable_psr2_transcoder_exitline(const struct intel_crtc_state *cstate)
+{
+	u32 linetime_us, val, exit_scanlines;
+	u32 crtc_vdisplay = cstate->base.adjusted_mode.crtc_vdisplay;
+	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+
+	linetime_us = fixed16_to_u32_round_up(intel_get_linetime_us(cstate));
+	if (WARN_ON(!linetime_us))
+		return;
+	/*
+	 * DC3CO Exit time 200us B.Spec 49196
+	 * PSR2 transcoder Early Exit scanlines = ROUNDUP(200 / line time) + 1
+	 * Exit line event need to program above calculated scan lines before
+	 * next VBLANK.
+	 */
+	exit_scanlines = DIV_ROUND_UP(200, linetime_us) + 1;
+	if (WARN_ON(exit_scanlines > crtc_vdisplay))
+		return;
+
+	exit_scanlines = crtc_vdisplay - exit_scanlines;
+	exit_scanlines <<= EXITLINE_SHIFT;
+	val = I915_READ(EXITLINE(cstate->cpu_transcoder));
+	val &= ~(EXITLINE_MASK | EXITLINE_ENABLE);
+	val |= exit_scanlines;
+	val |= EXITLINE_ENABLE;
+	I915_WRITE(EXITLINE(cstate->cpu_transcoder), val);
+}
+
+static bool tgl_dc3co_is_edp_connected(struct intel_crtc_state  *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->base.state;
+	struct drm_connector *connector;
+	struct drm_connector_state *connector_state;
+	int i;
+
+	for_each_new_connector_in_state(state, connector, connector_state, i) {
+		if (connector->status == connector_status_connected &&
+		    connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/*
+ * DC3CO requires to enable exitline and program DC3CO requires
+ * exit scanlines to TRANS_EXITLINE register, which should only
+ * change before transcoder or port is enabled.
+ * This requires to disable the fastset at boot for eDP output.
+ */
+bool tgl_dc3co_can_enable_fastset(struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+	bool fastset = true;
+
+	if (!IS_TIGERLAKE(dev_priv))
+		return fastset;
+
+	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
+		return fastset;
+
+	if (crtc_state->has_psr2 && crtc_state->base.active) {
+		if (tgl_dc3co_is_edp_connected(crtc_state)) {
+			if (!dev_priv->csr.dc3co_boot_modeset) {
+				fastset = false;
+				dev_priv->csr.dc3co_boot_modeset = true;
+			}
+		}
+	}
+
+	return fastset;
+}
+
+void tgl_compute_dc3co_crtc(struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+	dev_priv->csr.dc3co_crtc = NULL;
+
+	if (!IS_TIGERLAKE(dev_priv))
+		return;
+
+	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
+		return;
+
+	if (crtc_state->has_psr2 && crtc_state->base.active) {
+		if (tgl_dc3co_is_edp_connected(crtc_state)) {
+			dev_priv->csr.dc3co_crtc =
+				to_intel_crtc(crtc_state->base.crtc);
+		}
+	}
+}
+
 static void tgl_allow_dc3co(struct drm_i915_private *dev_priv)
 {
 	if (!dev_priv->psr.sink_psr2_support)
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 1add626da458..c37c4ce24a5f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -12,6 +12,8 @@ 
 
 struct drm_i915_private;
 struct intel_encoder;
+struct intel_crtc_state;
+struct intel_atomic_state;
 
 enum intel_display_power_domain {
 	POWER_DOMAIN_DISPLAY_CORE,
@@ -258,6 +260,10 @@  void intel_display_power_resume_early(struct drm_i915_private *i915);
 void intel_display_power_suspend(struct drm_i915_private *i915);
 void intel_display_power_resume(struct drm_i915_private *i915);
 void tgl_set_target_dc_state(struct drm_i915_private *dev_priv, u32 state);
+bool tgl_dc3co_can_enable_fastset(struct intel_crtc_state *crtc_state);
+void tgl_compute_dc3co_crtc(struct intel_crtc_state *crtc_state);
+void tgl_dc5_idle_thread(struct work_struct *work);
+void tgl_enable_psr2_transcoder_exitline(const struct intel_crtc_state *cstate);
 
 const char *
 intel_display_power_domain_str(enum intel_display_power_domain domain);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 999da5d2da0b..d593980e3d51 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -339,6 +339,9 @@  struct intel_csr {
 	u32 max_dc_state;
 	u32 allowed_dc_mask;
 	intel_wakeref_t wakeref;
+	bool dc3co_boot_modeset;
+	/* cache the crtc on which DC3CO will be allowed */
+	struct intel_crtc *dc3co_crtc;
 };
 
 enum i915_cache_level {
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 4fa9bc83c8b4..3ee104ae3e2d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -4584,7 +4584,7 @@  skl_wm_method2(u32 pixel_rate, u32 pipe_htotal, u32 latency,
 	return ret;
 }
 
-static uint_fixed_16_16_t
+uint_fixed_16_16_t
 intel_get_linetime_us(const struct intel_crtc_state *crtc_state)
 {
 	u32 pixel_rate;
diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h
index e3573e1e16e3..454e92c06dff 100644
--- a/drivers/gpu/drm/i915/intel_pm.h
+++ b/drivers/gpu/drm/i915/intel_pm.h
@@ -8,6 +8,7 @@ 
 
 #include <linux/types.h>
 
+#include "i915_drv.h"
 #include "i915_reg.h"
 
 struct drm_device;
@@ -76,6 +77,7 @@  u64 intel_rc6_residency_ns(struct drm_i915_private *dev_priv, i915_reg_t reg);
 u64 intel_rc6_residency_us(struct drm_i915_private *dev_priv, i915_reg_t reg);
 
 u32 intel_get_cagf(struct drm_i915_private *dev_priv, u32 rpstat1);
+uint_fixed_16_16_t intel_get_linetime_us(const struct intel_crtc_state *cstate);
 
 unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 unsigned long i915_mch_val(struct drm_i915_private *dev_priv);