All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl.
@ 2014-01-23 18:16 Rodrigo Vivi
  2014-01-23 18:16 ` [PATCH 2/4] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
                   ` (3 more replies)
  0 siblings, 4 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 18:16 UTC (permalink / raw)
  To: intel-gfx

This patch allows system to safely recover after kms_psr_sink_crc check
or any other similar case that might fail when PSR is enabled.

Ville made and sent me this patch after noticing that primary plane enabled
bit was set during test case and unset after failure. What was causing a hard
and non-recoverable blank screen.

After the failure when alternating from fbcon to x section it was possible to
see and move mouse cursor, but nothing else. Everything else was fully black.
A for dpms off/on also haleped to get screen back. But this patch seeting
primary plane enabled bit propertly seemed more clean.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dde98020..6592ad7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2095,6 +2095,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	if (IS_G4X(dev))
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+		dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -2192,6 +2195,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	else
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+                dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -8586,6 +8592,10 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 	intel_ring_emit(ring, (MI_NOOP));
 
+	if (IS_VALLEYVIEW(dev) && intel_crtc->primary_enabled)
+		I915_WRITE(DSPCNTR(intel_crtc->plane),
+			I915_READ(DSPCNTR(intel_crtc->plane)) | DISPLAY_PLANE_ENABLE);
+
 	intel_mark_page_flip_active(intel_crtc);
 	__intel_ring_advance(ring);
 	return 0;
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 2/4] drm/i915: move psr_setup_done to psr struct
  2014-01-23 18:16 [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
@ 2014-01-23 18:16 ` Rodrigo Vivi
  2014-01-24 14:50   ` Ville Syrjälä
  2014-01-23 18:16 ` [PATCH 3/4] drm/i915: Update PSR on resume Rodrigo Vivi
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 18:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

v2: Avoid more than one setup. Removing initialization
    and trusting allocation. (By Paulo Zanoni).

Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_drv.h  | 1 +
 drivers/gpu/drm/i915/intel_dp.c  | 6 ++----
 drivers/gpu/drm/i915/intel_drv.h | 1 -
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 29e1e86..fd5fc4b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -744,6 +744,7 @@ struct i915_fbc {
 struct i915_psr {
 	bool sink_support;
 	bool source_ok;
+	bool setup_done;
 };
 
 enum intel_pch {
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index dc646ac..b082973 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1568,7 +1568,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
 
-	if (intel_dp->psr_setup_done)
+	if (dev_priv->psr.setup_done)
 		return;
 
 	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
@@ -1583,7 +1583,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
 		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
 
-	intel_dp->psr_setup_done = true;
+	dev_priv->psr.setup_done = true;
 }
 
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
@@ -3733,8 +3733,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
 	     error, port_name(port));
 
-	intel_dp->psr_setup_done = false;
-
 	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
 		i2c_del_adapter(&intel_dp->adapter);
 		if (is_edp(intel_dp)) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b19a43d..f3959f1 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -487,7 +487,6 @@ struct intel_dp {
 	int backlight_off_delay;
 	struct delayed_work panel_vdd_work;
 	bool want_panel_vdd;
-	bool psr_setup_done;
 	struct intel_connector *attached_connector;
 };
 
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 3/4] drm/i915: Update PSR on resume.
  2014-01-23 18:16 [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
  2014-01-23 18:16 ` [PATCH 2/4] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
@ 2014-01-23 18:16 ` Rodrigo Vivi
  2014-02-05 19:04   ` [PATCH 1/2] " Rodrigo Vivi
  2014-01-23 18:16 ` [PATCH 4/4] drm/i915: Add Baytrail PSR Support Rodrigo Vivi
  2014-01-23 19:19 ` [PATCH] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
  3 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 18:16 UTC (permalink / raw)
  To: intel-gfx

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_suspend.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 8150fdc..641faee 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -298,6 +298,9 @@ static void i915_restore_display(struct drm_device *dev)
 		I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
 	}
 
+	dev_priv->psr.setup_done = false;
+	intel_edp_psr_update(dev);
+
 	/* only restore FBC info on the platform that supports FBC*/
 	intel_disable_fbc(dev);
 	if (HAS_FBC(dev)) {
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 4/4] drm/i915: Add Baytrail PSR Support.
  2014-01-23 18:16 [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
  2014-01-23 18:16 ` [PATCH 2/4] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
  2014-01-23 18:16 ` [PATCH 3/4] drm/i915: Update PSR on resume Rodrigo Vivi
@ 2014-01-23 18:16 ` Rodrigo Vivi
  2014-01-23 19:19   ` [PATCH] " Rodrigo Vivi
  2014-01-23 19:19 ` [PATCH] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
  3 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 18:16 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  18 +++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   9 ++
 drivers/gpu/drm/i915/i915_reg.h      |  34 ++++++++
 drivers/gpu/drm/i915/intel_ddi.c     |   3 +-
 drivers/gpu/drm/i915/intel_display.c |  14 ++++
 drivers/gpu/drm/i915/intel_dp.c      | 154 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 8 files changed, 206 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a1d29d1..d9603ff 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1902,6 +1902,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 psrstatus;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1909,14 +1910,23 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			     psrstatus = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((psrstatus == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (psrstatus == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 	seq_printf(m, "Enabled: %s\n", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index fd5fc4b..e4c7157 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -745,6 +745,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1871,7 +1872,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index bd93534..454d16e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	/* Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4047,6 +4053,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 76126e0..f5501ab 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1969,6 +1969,40 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define VLV_EDP_PSR_CTL				(VLV_DISPLAY_BASE + 0x60090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+
+#define VLV_PIPEA_VSC_SDP_REG		(VLV_DISPLAY_BASE + 0x600a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+
+#define VLV_EDP_PSR_STATUS_CTL		(VLV_DISPLAY_BASE + 0x60094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+
+#define VLV_PSR_CLK_GATE_DISABLE	(VLV_DISPLAY_BASE + 0x6204)
+#define  VLV_CLK_DISABLE_PIPE_B		(1<<30)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 74749c6..b40775c 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1281,7 +1281,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 			intel_dp_stop_link_train(intel_dp);
 
 		ironlake_edp_backlight_on(intel_dp);
-		intel_edp_psr_enable(intel_dp);
+		if (!IS_VALLEYVIEW(dev))
+			intel_edp_psr_enable(intel_dp);
 	}
 
 	if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6592ad7..21ba10c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7474,6 +7474,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8175,6 +8178,9 @@ void intel_mark_idle(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
+
 	hsw_package_c8_gpu_idle(dev_priv);
 
 	if (!i915_powersave)
@@ -8191,12 +8197,16 @@ void intel_mark_idle(struct drm_device *dev)
 		gen6_rps_idle(dev->dev_private);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (!i915_powersave)
 		return;
 
@@ -8646,6 +8656,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b082973..b6b770a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1526,11 +1526,19 @@ static bool is_edp_psr(struct drm_device *dev)
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			val = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			return ((val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1567,25 +1575,44 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_PIPEA_VSC_SDP_REG);
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_PIPEA_VSC_SDP_REG, val);
+
+		val = I915_READ(VLV_PSR_CLK_GATE_DISABLE);
+		val |= VLV_CLK_DISABLE_PIPE_B;
+		I915_WRITE(VLV_PSR_CLK_GATE_DISABLE, val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1614,6 +1641,24 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1655,8 +1700,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1708,28 +1753,54 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
+	if (intel_edp_is_psr_enabled(dev))
 		return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
+	if (intel_edp_psr_match_conditions(intel_dp))
+		intel_edp_psr_do_enable(intel_dp);
+}
+
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL);
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
-		intel_edp_psr_do_enable(intel_dp);
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
 }
 
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
@@ -1761,20 +1832,52 @@ void intel_edp_psr_update(struct drm_device *dev)
 			if (!is_edp_psr(dev))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+
+			if (!is_edp_psr(dev))
+				return;
+
+			dev_priv->psr.active = false;
+
+			I915_WRITE(VLV_EDP_PSR_CTL, VLV_EDP_PSR_RESET);
+			I915_WRITE(VLV_EDP_PSR_CTL, 0);
+			POSTING_READ(VLV_EDP_PSR_CTL);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	ironlake_edp_backlight_off(intel_dp);
@@ -1831,6 +1934,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	ironlake_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f3959f1..75131a2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -735,6 +735,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH] drm/i915: Set primary plane enable at dpcntrl.
  2014-01-23 18:16 [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
                   ` (2 preceding siblings ...)
  2014-01-23 18:16 ` [PATCH 4/4] drm/i915: Add Baytrail PSR Support Rodrigo Vivi
@ 2014-01-23 19:19 ` Rodrigo Vivi
  2014-01-24 14:58   ` Ville Syrjälä
  3 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 19:19 UTC (permalink / raw)
  To: intel-gfx

This patch allows system to safely recover after kms_psr_sink_crc check
or any other similar case that might fail when PSR is enabled.

Ville made and sent me this patch after noticing that primary plane enabled
bit was set during test case and unset after failure. What was causing a hard
and non-recoverable blank screen.

After the failure when alternating from fbcon to x section it was possible to
see and move mouse cursor, but nothing else. Everything else was fully black.
A for dpms off/on also haleped to get screen back. But this patch seeting
primary plane enabled bit propertly seemed more clean.

v2: Fix identation issue.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_display.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dde98020..ed5ffce 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2095,6 +2095,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	if (IS_G4X(dev))
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+		dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -2192,6 +2195,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	else
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+		dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -8586,6 +8592,11 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 	intel_ring_emit(ring, (MI_NOOP));
 
+	if (IS_VALLEYVIEW(dev) && intel_crtc->primary_enabled)
+		I915_WRITE(DSPCNTR(intel_crtc->plane),
+			   I915_READ(DSPCNTR(intel_crtc->plane))
+			   | DISPLAY_PLANE_ENABLE);
+
 	intel_mark_page_flip_active(intel_crtc);
 	__intel_ring_advance(ring);
 	return 0;
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-23 18:16 ` [PATCH 4/4] drm/i915: Add Baytrail PSR Support Rodrigo Vivi
@ 2014-01-23 19:19   ` Rodrigo Vivi
  2014-01-24 14:53     ` Ville Syrjälä
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-23 19:19 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  18 +++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   9 ++
 drivers/gpu/drm/i915/i915_reg.h      |  34 ++++++++
 drivers/gpu/drm/i915/intel_ddi.c     |   3 +-
 drivers/gpu/drm/i915/intel_display.c |  14 ++++
 drivers/gpu/drm/i915/intel_dp.c      | 154 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 8 files changed, 206 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a1d29d1..5dfde84 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1902,6 +1902,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 psrstatus;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1909,14 +1910,23 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			psrstatus = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((psrstatus == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (psrstatus == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 	seq_printf(m, "Enabled: %s\n", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index fd5fc4b..e4c7157 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -745,6 +745,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1871,7 +1872,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index bd93534..454d16e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	/* Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4047,6 +4053,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 76126e0..f5501ab 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1969,6 +1969,40 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define VLV_EDP_PSR_CTL				(VLV_DISPLAY_BASE + 0x60090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+
+#define VLV_PIPEA_VSC_SDP_REG		(VLV_DISPLAY_BASE + 0x600a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+
+#define VLV_EDP_PSR_STATUS_CTL		(VLV_DISPLAY_BASE + 0x60094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+
+#define VLV_PSR_CLK_GATE_DISABLE	(VLV_DISPLAY_BASE + 0x6204)
+#define  VLV_CLK_DISABLE_PIPE_B		(1<<30)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 74749c6..b40775c 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1281,7 +1281,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 			intel_dp_stop_link_train(intel_dp);
 
 		ironlake_edp_backlight_on(intel_dp);
-		intel_edp_psr_enable(intel_dp);
+		if (!IS_VALLEYVIEW(dev))
+			intel_edp_psr_enable(intel_dp);
 	}
 
 	if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ed5ffce..5be75c2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7474,6 +7474,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8175,6 +8178,9 @@ void intel_mark_idle(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
+
 	hsw_package_c8_gpu_idle(dev_priv);
 
 	if (!i915_powersave)
@@ -8191,12 +8197,16 @@ void intel_mark_idle(struct drm_device *dev)
 		gen6_rps_idle(dev->dev_private);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (!i915_powersave)
 		return;
 
@@ -8647,6 +8657,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b082973..163170c 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1526,11 +1526,19 @@ static bool is_edp_psr(struct drm_device *dev)
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			val = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
+		} else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1567,25 +1575,44 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_PIPEA_VSC_SDP_REG);
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_PIPEA_VSC_SDP_REG, val);
+
+		val = I915_READ(VLV_PSR_CLK_GATE_DISABLE);
+		val |= VLV_CLK_DISABLE_PIPE_B;
+		I915_WRITE(VLV_PSR_CLK_GATE_DISABLE, val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1614,6 +1641,24 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1655,8 +1700,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1708,28 +1753,54 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
+	if (intel_edp_is_psr_enabled(dev))
 		return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
+	if (intel_edp_psr_match_conditions(intel_dp))
+		intel_edp_psr_do_enable(intel_dp);
+}
+
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL);
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
-		intel_edp_psr_do_enable(intel_dp);
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
 }
 
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
@@ -1761,20 +1832,52 @@ void intel_edp_psr_update(struct drm_device *dev)
 			if (!is_edp_psr(dev))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+
+			if (!is_edp_psr(dev))
+				return;
+
+			dev_priv->psr.active = false;
+
+			I915_WRITE(VLV_EDP_PSR_CTL, VLV_EDP_PSR_RESET);
+			I915_WRITE(VLV_EDP_PSR_CTL, 0);
+			POSTING_READ(VLV_EDP_PSR_CTL);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	ironlake_edp_backlight_off(intel_dp);
@@ -1831,6 +1934,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	ironlake_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f3959f1..75131a2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -735,6 +735,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/4] drm/i915: move psr_setup_done to psr struct
  2014-01-23 18:16 ` [PATCH 2/4] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
@ 2014-01-24 14:50   ` Ville Syrjälä
  2014-01-24 16:02     ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-24 14:50 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx, Paulo Zanoni

On Thu, Jan 23, 2014 at 04:16:48PM -0200, Rodrigo Vivi wrote:
> v2: Avoid more than one setup. Removing initialization
>     and trusting allocation. (By Paulo Zanoni).

And what about doing PSR w/ two eDP panels on VLV? The hardware should
support it.

> 
> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h  | 1 +
>  drivers/gpu/drm/i915/intel_dp.c  | 6 ++----
>  drivers/gpu/drm/i915/intel_drv.h | 1 -
>  3 files changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 29e1e86..fd5fc4b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -744,6 +744,7 @@ struct i915_fbc {
>  struct i915_psr {
>  	bool sink_support;
>  	bool source_ok;
> +	bool setup_done;
>  };
>  
>  enum intel_pch {
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index dc646ac..b082973 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1568,7 +1568,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct edp_vsc_psr psr_vsc;
>  
> -	if (intel_dp->psr_setup_done)
> +	if (dev_priv->psr.setup_done)
>  		return;
>  
>  	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> @@ -1583,7 +1583,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>  	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>  		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>  
> -	intel_dp->psr_setup_done = true;
> +	dev_priv->psr.setup_done = true;
>  }
>  
>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> @@ -3733,8 +3733,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  	WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
>  	     error, port_name(port));
>  
> -	intel_dp->psr_setup_done = false;
> -
>  	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
>  		i2c_del_adapter(&intel_dp->adapter);
>  		if (is_edp(intel_dp)) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index b19a43d..f3959f1 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -487,7 +487,6 @@ struct intel_dp {
>  	int backlight_off_delay;
>  	struct delayed_work panel_vdd_work;
>  	bool want_panel_vdd;
> -	bool psr_setup_done;
>  	struct intel_connector *attached_connector;
>  };
>  
> -- 
> 1.8.1.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-23 19:19   ` [PATCH] " Rodrigo Vivi
@ 2014-01-24 14:53     ` Ville Syrjälä
  2014-01-24 16:05       ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-24 14:53 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Thu, Jan 23, 2014 at 05:19:53PM -0200, Rodrigo Vivi wrote:
<snip>
> index 76126e0..f5501ab 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -1969,6 +1969,40 @@
>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>  
> +/* VLV eDP PSR registers */
> +#define VLV_EDP_PSR_CTL				(VLV_DISPLAY_BASE + 0x60090)

VLV has per-pipe PSR registers. The ones you have here are just for
pipe A. Seems like some rework is needed to make it work on either
pipe.


-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Set primary plane enable at dpcntrl.
  2014-01-23 19:19 ` [PATCH] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
@ 2014-01-24 14:58   ` Ville Syrjälä
  2014-01-28 19:46     ` [PATCH 1/4] " Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-24 14:58 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Thu, Jan 23, 2014 at 05:19:19PM -0200, Rodrigo Vivi wrote:
> This patch allows system to safely recover after kms_psr_sink_crc check
> or any other similar case that might fail when PSR is enabled.
> 
> Ville made and sent me this patch after noticing that primary plane enabled
> bit was set during test case and unset after failure. What was causing a hard
> and non-recoverable blank screen.
> 
> After the failure when alternating from fbcon to x section it was possible to
> see and move mouse cursor, but nothing else. Everything else was fully black.
> A for dpms off/on also haleped to get screen back. But this patch seeting
> primary plane enabled bit propertly seemed more clean.
> 
> v2: Fix identation issue.
> 
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index dde98020..ed5ffce 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2095,6 +2095,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	if (IS_G4X(dev))
>  		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
>  
> +	if (intel_crtc->primary_enabled)
> +		dspcntr |= DISPLAY_PLANE_ENABLE;
> +
>  	I915_WRITE(reg, dspcntr);
>  
>  	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
> @@ -2192,6 +2195,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
>  	else
>  		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
>  
> +	if (intel_crtc->primary_enabled)
> +		dspcntr |= DISPLAY_PLANE_ENABLE;
> +
>  	I915_WRITE(reg, dspcntr);
>  
>  	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
> @@ -8586,6 +8592,11 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
>  	intel_ring_emit(ring, (MI_NOOP));
>  
> +	if (IS_VALLEYVIEW(dev) && intel_crtc->primary_enabled)
> +		I915_WRITE(DSPCNTR(intel_crtc->plane),
> +			   I915_READ(DSPCNTR(intel_crtc->plane))
> +			   | DISPLAY_PLANE_ENABLE);

We should add some kind of big comment that this ugly hack is here for
PSR. I assume we're going to remove it eventually once someone figures
out why the port/pipe/PLL aren't shutting down during PSR. To wake the
hardware back from that state takes a lot more than just flipping a
plane enable bit.

> +
>  	intel_mark_page_flip_active(intel_crtc);
>  	__intel_ring_advance(ring);
>  	return 0;
> -- 
> 1.8.1.2

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/4] drm/i915: move psr_setup_done to psr struct
  2014-01-24 14:50   ` Ville Syrjälä
@ 2014-01-24 16:02     ` Rodrigo Vivi
  0 siblings, 0 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-24 16:02 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, Paulo Zanoni

On Fri, Jan 24, 2014 at 12:50 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Thu, Jan 23, 2014 at 04:16:48PM -0200, Rodrigo Vivi wrote:
>> v2: Avoid more than one setup. Removing initialization
>>     and trusting allocation. (By Paulo Zanoni).
>
> And what about doing PSR w/ two eDP panels on VLV? The hardware should
> support it.

I'm afraid my comment here wasn't clear, sorry.
What I meant was to avoid restart setup_done status.... setup_done
should be called only once but this initializatio was in a place been
called more than once.
Nothing to do with more than one panel here.

>
>>
>> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
>> ---
>>  drivers/gpu/drm/i915/i915_drv.h  | 1 +
>>  drivers/gpu/drm/i915/intel_dp.c  | 6 ++----
>>  drivers/gpu/drm/i915/intel_drv.h | 1 -
>>  3 files changed, 3 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> index 29e1e86..fd5fc4b 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -744,6 +744,7 @@ struct i915_fbc {
>>  struct i915_psr {
>>       bool sink_support;
>>       bool source_ok;
>> +     bool setup_done;
>>  };
>>
>>  enum intel_pch {
>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> index dc646ac..b082973 100644
>> --- a/drivers/gpu/drm/i915/intel_dp.c
>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> @@ -1568,7 +1568,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct edp_vsc_psr psr_vsc;
>>
>> -     if (intel_dp->psr_setup_done)
>> +     if (dev_priv->psr.setup_done)
>>               return;
>>
>>       /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> @@ -1583,7 +1583,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>>       I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>>                  EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>>
>> -     intel_dp->psr_setup_done = true;
>> +     dev_priv->psr.setup_done = true;
>>  }
>>
>>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> @@ -3733,8 +3733,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>>       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
>>            error, port_name(port));
>>
>> -     intel_dp->psr_setup_done = false;
>> -
>>       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
>>               i2c_del_adapter(&intel_dp->adapter);
>>               if (is_edp(intel_dp)) {
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index b19a43d..f3959f1 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -487,7 +487,6 @@ struct intel_dp {
>>       int backlight_off_delay;
>>       struct delayed_work panel_vdd_work;
>>       bool want_panel_vdd;
>> -     bool psr_setup_done;
>>       struct intel_connector *attached_connector;
>>  };
>>
>> --
>> 1.8.1.2
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Ville Syrjälä
> Intel OTC



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-24 14:53     ` Ville Syrjälä
@ 2014-01-24 16:05       ` Rodrigo Vivi
  2014-01-24 17:41         ` Ville Syrjälä
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-24 16:05 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Fri, Jan 24, 2014 at 12:53 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Thu, Jan 23, 2014 at 05:19:53PM -0200, Rodrigo Vivi wrote:
> <snip>
>> index 76126e0..f5501ab 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -1969,6 +1969,40 @@
>>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>>
>> +/* VLV eDP PSR registers */
>> +#define VLV_EDP_PSR_CTL                              (VLV_DISPLAY_BASE + 0x60090)
>
> VLV has per-pipe PSR registers. The ones you have here are just for
> pipe A. Seems like some rework is needed to make it work on either
> pipe.

Yes, but since I don't have any hw with two eDPs here I decided to let
the limitation we had for HSW, PSR only on pipe A.
In my point of view we could go ahead with this one eDP scenario and
implement psr on pipe b support later.

>
>
> --
> Ville Syrjälä
> Intel OTC



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-24 16:05       ` Rodrigo Vivi
@ 2014-01-24 17:41         ` Ville Syrjälä
  2014-01-28 19:47           ` [PATCH 4/4] " Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-24 17:41 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Fri, Jan 24, 2014 at 02:05:57PM -0200, Rodrigo Vivi wrote:
> On Fri, Jan 24, 2014 at 12:53 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Thu, Jan 23, 2014 at 05:19:53PM -0200, Rodrigo Vivi wrote:
> > <snip>
> >> index 76126e0..f5501ab 100644
> >> --- a/drivers/gpu/drm/i915/i915_reg.h
> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
> >> @@ -1969,6 +1969,40 @@
> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
> >>
> >> +/* VLV eDP PSR registers */
> >> +#define VLV_EDP_PSR_CTL                              (VLV_DISPLAY_BASE + 0x60090)
> >
> > VLV has per-pipe PSR registers. The ones you have here are just for
> > pipe A. Seems like some rework is needed to make it work on either
> > pipe.
> 
> Yes, but since I don't have any hw with two eDPs here I decided to let
> the limitation we had for HSW, PSR only on pipe A.
> In my point of view we could go ahead with this one eDP scenario and
> implement psr on pipe b support later.

I don't see any pipe checks in the code, so you will happily enable PSR
on pipe A even if eDP is being fed by pipe B at the time.

Also even if you enable PSR on pipe A, you set the trunk clock gate
disable for pipe B, which seems weird. Setting that bit might actually
be the reason the pipe, port and PLL remain enabled during PSR.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl.
  2014-01-24 14:58   ` Ville Syrjälä
@ 2014-01-28 19:46     ` Rodrigo Vivi
  0 siblings, 0 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-28 19:46 UTC (permalink / raw)
  To: intel-gfx

This patch allows system to safely recover after kms_psr_sink_crc check
or any other similar case that might fail when PSR is enabled.

Ville made and sent me this patch after noticing that primary plane enabled
bit was set during test case and unset after failure. What was causing a hard
and non-recoverable blank screen.

After the failure when alternating from fbcon to x section it was possible to
see and move mouse cursor, but nothing else. Everything else was fully black.
A for dpms off/on also haleped to get screen back. But this patch seeting
primary plane enabled bit propertly seemed more clean.

v2: Fix identation issue.
v3: Add the XXX comment.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 122f871..1a9aa19 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2095,6 +2095,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	if (IS_G4X(dev))
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+		dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -2192,6 +2195,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 	else
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+	if (intel_crtc->primary_enabled)
+		dspcntr |= DISPLAY_PLANE_ENABLE;
+
 	I915_WRITE(reg, dspcntr);
 
 	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -8625,6 +8631,13 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 	intel_ring_emit(ring, (MI_NOOP));
 
+	/* XXX: Ugly hack to avoid PSR test case eventually breaking things up
+	 * to be removed whenever it is fixed. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->primary_enabled)
+		I915_WRITE(DSPCNTR(intel_crtc->plane),
+			   I915_READ(DSPCNTR(intel_crtc->plane))
+			   | DISPLAY_PLANE_ENABLE);
+
 	intel_mark_page_flip_active(intel_crtc);
 	__intel_ring_advance(ring);
 	return 0;
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 4/4] drm/i915: Add Baytrail PSR Support.
  2014-01-24 17:41         ` Ville Syrjälä
@ 2014-01-28 19:47           ` Rodrigo Vivi
  2014-01-29 12:47             ` [PATCH] " Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-28 19:47 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.
v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
    support disabled by for now since it isn't working properly yet.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 +++++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   9 ++
 drivers/gpu/drm/i915/i915_reg.h      |  40 +++++++
 drivers/gpu/drm/i915/intel_display.c |  15 ++-
 drivers/gpu/drm/i915/intel_dp.c      | 208 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 7 files changed, 274 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 4b852c6..c28de65 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 statA = 0;
+	u32 statB = 0;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "Enabled: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
+	seq_printf(m, "Enabled: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (IS_VALLEYVIEW(dev)) {
+		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe A");
+		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe B");
+	}
+
+	seq_puts(m, "\n");
+
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7c53d4d..34dee24 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,6 +747,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39770f7..01137fe 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	/* Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cbbaf26..3a34afb 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1968,6 +1968,46 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_EDP_VSC_SDP_REG(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
+#define VLV_PSR_CLK_GATE_DISABLE	(VLV_DISPLAY_BASE + 0x6204)
+#define  VLV_CLK_DISABLE_PIPE_B		(1<<30)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a9aa19..081c8e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
 
 	if (dev_priv->info->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
-	if (!i915.powersave)
-		return;
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (!crtc->fb)
@@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 30d4350..b1164ff 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
-static bool is_edp_psr(struct drm_device *dev)
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	return dev_priv->psr.sink_support;
+	val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
+		VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev))
+			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
+				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
+		else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1626,28 +1640,53 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
 
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
+
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
+
+		/* val = I915_READ(VLV_PSR_CLK_GATE_DISABLE); */
+		/* val |= VLV_CLK_DISABLE_PIPE_B; */
+		/* I915_WRITE(VLV_PSR_CLK_GATE_DISABLE, val); */
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1678,6 +1717,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1719,8 +1780,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1765,37 +1826,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	/* Baytrail supports per-pipe PSR configuration, however PSR on
+	* PIPE_B isn't working properly. So let's keep it disabled for now. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
+		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
+		return false;
+	}
+
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
+	if (IS_VALLEYVIEW(dev)) {
+		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
+			return;
+	} else
+		if (intel_edp_is_psr_enabled(dev))
+			return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	if (!is_edp_psr(intel_dp))
+		return;
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
+	if (intel_edp_psr_match_conditions(intel_dp))
 		intel_edp_psr_do_enable(intel_dp);
 }
 
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1817,28 +1924,66 @@ void intel_edp_psr_update(struct drm_device *dev)
 {
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
+	struct intel_crtc *intel_crtc;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
 
-			if (!is_edp_psr(dev))
+			if (!is_edp_psr(intel_dp))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_crtc *intel_crtc;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
+							    intel_crtc->pipe))
+				continue;
+
+			dev_priv->psr.active = false;
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
+				   VLV_EDP_PSR_RESET);
+			/* WaClearPSRReset:vlv */
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_backlight_off(intel_dp);
@@ -1895,6 +2040,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 71c1371..82026ef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-28 19:47           ` [PATCH 4/4] " Rodrigo Vivi
@ 2014-01-29 12:47             ` Rodrigo Vivi
  2014-01-29 13:12               ` Chris Wilson
  2014-01-29 14:56               ` Ville Syrjälä
  0 siblings, 2 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 12:47 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.
v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
    support disabled by for now since it isn't working properly yet.
v6: Removing forgotten comment and useless clkgating definition.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   9 ++
 drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
 drivers/gpu/drm/i915/intel_display.c |  15 ++-
 drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 7 files changed, 267 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 4b852c6..c28de65 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 statA = 0;
+	u32 statB = 0;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "Enabled: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
+	seq_printf(m, "Enabled: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (IS_VALLEYVIEW(dev)) {
+		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe A");
+		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe B");
+	}
+
+	seq_puts(m, "\n");
+
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7c53d4d..34dee24 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,6 +747,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39770f7..01137fe 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	/* Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cbbaf26..2039d71 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1968,6 +1968,43 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_EDP_VSC_SDP_REG(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a9aa19..081c8e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
 
 	if (dev_priv->info->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
-	if (!i915.powersave)
-		return;
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (!crtc->fb)
@@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 30d4350..e9a0ace 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
-static bool is_edp_psr(struct drm_device *dev)
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	return dev_priv->psr.sink_support;
+	val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
+		VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev))
+			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
+				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
+		else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
 
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
+
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	/* Baytrail supports per-pipe PSR configuration, however PSR on
+	* PIPE_B isn't working properly. So let's keep it disabled for now. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
+		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
+		return false;
+	}
+
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
+	if (IS_VALLEYVIEW(dev)) {
+		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
+			return;
+	} else
+		if (intel_edp_is_psr_enabled(dev))
+			return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	if (!is_edp_psr(intel_dp))
+		return;
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
+	if (intel_edp_psr_match_conditions(intel_dp))
 		intel_edp_psr_do_enable(intel_dp);
 }
 
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
 {
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
+	struct intel_crtc *intel_crtc;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
 
-			if (!is_edp_psr(dev))
+			if (!is_edp_psr(intel_dp))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_crtc *intel_crtc;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
+							    intel_crtc->pipe))
+				continue;
+
+			dev_priv->psr.active = false;
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
+				   VLV_EDP_PSR_RESET);
+			/* WaClearPSRReset:vlv */
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_backlight_off(intel_dp);
@@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 71c1371..82026ef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 12:47             ` [PATCH] " Rodrigo Vivi
@ 2014-01-29 13:12               ` Chris Wilson
  2014-01-29 13:24                 ` Rodrigo Vivi
  2014-01-29 14:55                 ` Rodrigo Vivi
  2014-01-29 14:56               ` Ville Syrjälä
  1 sibling, 2 replies; 45+ messages in thread
From: Chris Wilson @ 2014-01-29 13:12 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> This patch adds PSR Support to Baytrail.
> 
> Baytrail cannot easily detect screen updates and force PSR exit.
> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> and update to enable it back on next display mark_idle.
> 
> v2: Also inactivate PSR on cursor update.
> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>     early on page flip besides avoid initializing inactive/active flag
>     more than once.
> v4: Fix identation issues.
> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>     support disabled by for now since it isn't working properly yet.
> v6: Removing forgotten comment and useless clkgating definition.

Not set-domain. This is semantically a flush and so should be after the
damage is done.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 13:12               ` Chris Wilson
@ 2014-01-29 13:24                 ` Rodrigo Vivi
  2014-01-29 13:27                   ` Chris Wilson
  2014-01-29 14:55                 ` Rodrigo Vivi
  1 sibling, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 13:24 UTC (permalink / raw)
  To: Chris Wilson, Rodrigo Vivi, intel-gfx

On Wed, Jan 29, 2014 at 11:12 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> This patch adds PSR Support to Baytrail.
>>
>> Baytrail cannot easily detect screen updates and force PSR exit.
>> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> and update to enable it back on next display mark_idle.
>>
>> v2: Also inactivate PSR on cursor update.
>> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>>     early on page flip besides avoid initializing inactive/active flag
>>     more than once.
>> v4: Fix identation issues.
>> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>>     support disabled by for now since it isn't working properly yet.
>> v6: Removing forgotten comment and useless clkgating definition.
>
> Not set-domain. This is semantically a flush and so should be after the
> damage is done.

Yep, I semantically I agree, but if we let to inactivate psr after
damage is done we will miss screen updates.
This was the safest way to get psr enabled and fully working and
passing crc tests.
If you have another place to suggest i'd be glad in do some tests
here, but for now this is the more stable place I know about.

> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 13:24                 ` Rodrigo Vivi
@ 2014-01-29 13:27                   ` Chris Wilson
  2014-01-29 13:54                     ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Chris Wilson @ 2014-01-29 13:27 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 11:24:44AM -0200, Rodrigo Vivi wrote:
> On Wed, Jan 29, 2014 at 11:12 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> >> This patch adds PSR Support to Baytrail.
> >>
> >> Baytrail cannot easily detect screen updates and force PSR exit.
> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> >> and update to enable it back on next display mark_idle.
> >>
> >> v2: Also inactivate PSR on cursor update.
> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >>     early on page flip besides avoid initializing inactive/active flag
> >>     more than once.
> >> v4: Fix identation issues.
> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >>     support disabled by for now since it isn't working properly yet.
> >> v6: Removing forgotten comment and useless clkgating definition.
> >
> > Not set-domain. This is semantically a flush and so should be after the
> > damage is done.
> 
> Yep, I semantically I agree, but if we let to inactivate psr after
> damage is done we will miss screen updates.
> This was the safest way to get psr enabled and fully working and
> passing crc tests.
> If you have another place to suggest i'd be glad in do some tests
> here, but for now this is the more stable place I know about.

It's the test that are at fault here for not following the established
ABI imo.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 13:27                   ` Chris Wilson
@ 2014-01-29 13:54                     ` Rodrigo Vivi
  2014-01-29 14:02                       ` Chris Wilson
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 13:54 UTC (permalink / raw)
  To: Chris Wilson, Rodrigo Vivi, intel-gfx

On Wed, Jan 29, 2014 at 11:27 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> On Wed, Jan 29, 2014 at 11:24:44AM -0200, Rodrigo Vivi wrote:
>> On Wed, Jan 29, 2014 at 11:12 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
>> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> >> This patch adds PSR Support to Baytrail.
>> >>
>> >> Baytrail cannot easily detect screen updates and force PSR exit.
>> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> >> and update to enable it back on next display mark_idle.
>> >>
>> >> v2: Also inactivate PSR on cursor update.
>> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>> >>     early on page flip besides avoid initializing inactive/active flag
>> >>     more than once.
>> >> v4: Fix identation issues.
>> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>> >>     support disabled by for now since it isn't working properly yet.
>> >> v6: Removing forgotten comment and useless clkgating definition.
>> >
>> > Not set-domain. This is semantically a flush and so should be after the
>> > damage is done.
>>
>> Yep, I semantically I agree, but if we let to inactivate psr after
>> damage is done we will miss screen updates.
>> This was the safest way to get psr enabled and fully working and
>> passing crc tests.
>> If you have another place to suggest i'd be glad in do some tests
>> here, but for now this is the more stable place I know about.
>
> It's the test that are at fault here for not following the established
> ABI imo.

this makes sense.

do we have this established ABI documented somewhere?

and what is missing on test? is it a busy ioctl in the end?

but anyway, doing this on set_domain we could fix the psr on
environments that doesn't follow this abi like KDE.

> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 13:54                     ` Rodrigo Vivi
@ 2014-01-29 14:02                       ` Chris Wilson
  2014-01-29 14:23                         ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Chris Wilson @ 2014-01-29 14:02 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 11:54:00AM -0200, Rodrigo Vivi wrote:
> On Wed, Jan 29, 2014 at 11:27 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > On Wed, Jan 29, 2014 at 11:24:44AM -0200, Rodrigo Vivi wrote:
> >> On Wed, Jan 29, 2014 at 11:12 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> >> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> >> >> This patch adds PSR Support to Baytrail.
> >> >>
> >> >> Baytrail cannot easily detect screen updates and force PSR exit.
> >> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> >> >> and update to enable it back on next display mark_idle.
> >> >>
> >> >> v2: Also inactivate PSR on cursor update.
> >> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >> >>     early on page flip besides avoid initializing inactive/active flag
> >> >>     more than once.
> >> >> v4: Fix identation issues.
> >> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >> >>     support disabled by for now since it isn't working properly yet.
> >> >> v6: Removing forgotten comment and useless clkgating definition.
> >> >
> >> > Not set-domain. This is semantically a flush and so should be after the
> >> > damage is done.
> >>
> >> Yep, I semantically I agree, but if we let to inactivate psr after
> >> damage is done we will miss screen updates.
> >> This was the safest way to get psr enabled and fully working and
> >> passing crc tests.
> >> If you have another place to suggest i'd be glad in do some tests
> >> here, but for now this is the more stable place I know about.
> >
> > It's the test that are at fault here for not following the established
> > ABI imo.
> 
> this makes sense.
> 
> do we have this established ABI documented somewhere?

Only what was established as required to make things work a few years
ago...
 
> and what is missing on test? is it a busy ioctl in the end?

busy or even a sw_finish. I see it already did the sw_finish. We have in
the past talked about formalizing the gap in the documentation with a
new call...
 
> but anyway, doing this on set_domain we could fix the psr on
> environments that doesn't follow this abi like KDE.

As we have discussed in the past, that is an issue in the ddx that
short-circuits the required flush if there was only GTT damage.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:02                       ` Chris Wilson
@ 2014-01-29 14:23                         ` Rodrigo Vivi
  2014-01-29 14:26                           ` Chris Wilson
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 14:23 UTC (permalink / raw)
  To: Chris Wilson, Rodrigo Vivi, intel-gfx

ok, got it.

So, the correct here is to remove inactivate from set_domain and add
gem_bo_busy call on MMAP_GTT testcase?

On Wed, Jan 29, 2014 at 12:02 PM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> On Wed, Jan 29, 2014 at 11:54:00AM -0200, Rodrigo Vivi wrote:
>> On Wed, Jan 29, 2014 at 11:27 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
>> > On Wed, Jan 29, 2014 at 11:24:44AM -0200, Rodrigo Vivi wrote:
>> >> On Wed, Jan 29, 2014 at 11:12 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
>> >> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> >> >> This patch adds PSR Support to Baytrail.
>> >> >>
>> >> >> Baytrail cannot easily detect screen updates and force PSR exit.
>> >> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> >> >> and update to enable it back on next display mark_idle.
>> >> >>
>> >> >> v2: Also inactivate PSR on cursor update.
>> >> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>> >> >>     early on page flip besides avoid initializing inactive/active flag
>> >> >>     more than once.
>> >> >> v4: Fix identation issues.
>> >> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>> >> >>     support disabled by for now since it isn't working properly yet.
>> >> >> v6: Removing forgotten comment and useless clkgating definition.
>> >> >
>> >> > Not set-domain. This is semantically a flush and so should be after the
>> >> > damage is done.
>> >>
>> >> Yep, I semantically I agree, but if we let to inactivate psr after
>> >> damage is done we will miss screen updates.
>> >> This was the safest way to get psr enabled and fully working and
>> >> passing crc tests.
>> >> If you have another place to suggest i'd be glad in do some tests
>> >> here, but for now this is the more stable place I know about.
>> >
>> > It's the test that are at fault here for not following the established
>> > ABI imo.
>>
>> this makes sense.
>>
>> do we have this established ABI documented somewhere?
>
> Only what was established as required to make things work a few years
> ago...
>
>> and what is missing on test? is it a busy ioctl in the end?
>
> busy or even a sw_finish. I see it already did the sw_finish. We have in
> the past talked about formalizing the gap in the documentation with a
> new call...
>
>> but anyway, doing this on set_domain we could fix the psr on
>> environments that doesn't follow this abi like KDE.
>
> As we have discussed in the past, that is an issue in the ddx that
> short-circuits the required flush if there was only GTT damage.
> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:23                         ` Rodrigo Vivi
@ 2014-01-29 14:26                           ` Chris Wilson
  2014-01-29 19:20                             ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Chris Wilson @ 2014-01-29 14:26 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 12:23:15PM -0200, Rodrigo Vivi wrote:
> ok, got it.
> 
> So, the correct here is to remove inactivate from set_domain and add
> gem_bo_busy call on MMAP_GTT testcase?

That would match what we should do today. It's just whether we take the
opportunity to define a consistent behaviour...
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 13:12               ` Chris Wilson
  2014-01-29 13:24                 ` Rodrigo Vivi
@ 2014-01-29 14:55                 ` Rodrigo Vivi
  2014-01-29 19:21                   ` Daniel Vetter
  1 sibling, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 14:55 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, sw_finish and mark_busy}
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.
v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
    support disabled by for now since it isn't working properly yet.
v6: Removing forgotten comment and useless clkgating definition.
v7: Remove inactivate from set_domain. Chris warned this was semanticaly
    wrong.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   6 ++
 drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
 drivers/gpu/drm/i915/intel_display.c |  15 ++-
 drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 7 files changed, 264 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 4b852c6..c28de65 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 statA = 0;
+	u32 statB = 0;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "Enabled: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
+	seq_printf(m, "Enabled: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (IS_VALLEYVIEW(dev)) {
+		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe A");
+		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe B");
+	}
+
+	seq_puts(m, "\n");
+
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7c53d4d..34dee24 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,6 +747,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39770f7..b3eec3b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1299,6 +1299,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4059,6 +4062,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cbbaf26..2039d71 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1968,6 +1968,43 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_EDP_VSC_SDP_REG(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a9aa19..081c8e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
 
 	if (dev_priv->info->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
-	if (!i915.powersave)
-		return;
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (!crtc->fb)
@@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 30d4350..e9a0ace 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
-static bool is_edp_psr(struct drm_device *dev)
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	return dev_priv->psr.sink_support;
+	val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
+		VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev))
+			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
+				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
+		else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
 
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
+
+		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	/* Baytrail supports per-pipe PSR configuration, however PSR on
+	* PIPE_B isn't working properly. So let's keep it disabled for now. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
+		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
+		return false;
+	}
+
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
+	if (IS_VALLEYVIEW(dev)) {
+		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
+			return;
+	} else
+		if (intel_edp_is_psr_enabled(dev))
+			return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	if (!is_edp_psr(intel_dp))
+		return;
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
+	if (intel_edp_psr_match_conditions(intel_dp))
 		intel_edp_psr_do_enable(intel_dp);
 }
 
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
+}
+
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
 {
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
+	struct intel_crtc *intel_crtc;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
 
-			if (!is_edp_psr(dev))
+			if (!is_edp_psr(intel_dp))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_crtc *intel_crtc;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
+							    intel_crtc->pipe))
+				continue;
+
+			dev_priv->psr.active = false;
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
+				   VLV_EDP_PSR_RESET);
+			/* WaClearPSRReset:vlv */
+			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_backlight_off(intel_dp);
@@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 71c1371..82026ef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 12:47             ` [PATCH] " Rodrigo Vivi
  2014-01-29 13:12               ` Chris Wilson
@ 2014-01-29 14:56               ` Ville Syrjälä
  2014-01-29 15:47                 ` Rodrigo Vivi
                                   ` (2 more replies)
  1 sibling, 3 replies; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-29 14:56 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> This patch adds PSR Support to Baytrail.
> 
> Baytrail cannot easily detect screen updates and force PSR exit.
> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> and update to enable it back on next display mark_idle.
> 
> v2: Also inactivate PSR on cursor update.
> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>     early on page flip besides avoid initializing inactive/active flag
>     more than once.
> v4: Fix identation issues.
> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>     support disabled by for now since it isn't working properly yet.
> v6: Removing forgotten comment and useless clkgating definition.
> 
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>  7 files changed, 267 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 4b852c6..c28de65 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>  	struct drm_device *dev = node->minor->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	u32 psrperf = 0;
> +	u32 statA = 0;
> +	u32 statB = 0;
>  	bool enabled = false;
>  
>  	intel_runtime_pm_get(dev_priv);
> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>  	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>  	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>  
> -	enabled = HAS_PSR(dev) &&
> -		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> -	seq_printf(m, "Enabled: %s\n", yesno(enabled));
> +	if (HAS_PSR(dev)) {
> +		if (IS_VALLEYVIEW(dev)) {
> +			statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
> +				VLV_EDP_PSR_CURR_STATE_MASK;
> +			statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
> +				VLV_EDP_PSR_CURR_STATE_MASK;
> +			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
> +				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
> +		} else
> +			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	}
> +	seq_printf(m, "Enabled: %s", yesno(enabled));
>  
> -	if (HAS_PSR(dev))
> +	if (IS_VALLEYVIEW(dev)) {
> +		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> +			seq_puts(m, " pipe A");
> +		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> +			seq_puts(m, " pipe B");
> +	}
> +
> +	seq_puts(m, "\n");
> +
> +	/* VLV PSR has no kind of performance counter */
> +	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>  		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>  			EDP_PSR_PERF_CNT_MASK;
> -	seq_printf(m, "Performance_Counter: %u\n", psrperf);
> +		seq_printf(m, "Performance_Counter: %u\n", psrperf);
> +	}
>  
>  	intel_runtime_pm_put(dev_priv);
>  	return 0;
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 7c53d4d..34dee24 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -747,6 +747,7 @@ struct i915_psr {
>  	bool sink_support;
>  	bool source_ok;
>  	bool setup_done;
> +	bool active;
>  };
>  
>  enum intel_pch {
> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
>  
>  #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
>  #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
> -#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
> +#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
> +				 IS_VALLEYVIEW(dev))
>  #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
>  #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 39770f7..01137fe 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>  		goto unlock;
>  	}
>  
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
> +
>  	/* Try to flush the object off the GPU without holding the lock.
>  	 * We will repeat the flush holding the lock in the normal manner
>  	 * to catch cases where we are gazumped.
> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>  	if (ret)
>  		return ret;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
> +
>  	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>  	if (&obj->base == NULL) {
>  		ret = -ENOENT;
> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>  	if (ret)
>  		return ret;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);

The locking for PSR seems to be as fubar as for FBC. Also the front
buffer tracking is missing, but I guess I need to make that work for FBC
first, and then we need to figure out how to tie it in w/ PSR.

> +
>  	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>  	if (&obj->base == NULL) {
>  		ret = -ENOENT;
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index cbbaf26..2039d71 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -1968,6 +1968,43 @@
>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>  
> +/* VLV eDP PSR registers */
> +#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
> +#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
> +#define  VLV_EDP_PSR_ENABLE			(1<<0)
> +#define  VLV_EDP_PSR_RESET			(1<<1)
> +#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
> +#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
> +#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
> +#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
> +#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
> +#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)

Can we just name the PSR registers like in the spec? Eg. just
VLV_PSRCTL(). Would make it easier to compare things w/ the spec.

> +
> +#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
> +#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
> +#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
> +#define VLV_EDP_VSC_SDP_REG(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
> +
> +#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
> +#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
> +#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
> +#define  VLV_EDP_PSR_CURR_STATE_MASK	7
> +#define  VLV_EDP_PSR_DISABLED		(0<<0)
> +#define  VLV_EDP_PSR_INACTIVE		(1<<0)
> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
> +#define  VLV_EDP_PSR_EXIT		(5<<0)
> +#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
> +
>  /* HSW+ eDP PSR registers */
>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>  #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 1a9aa19..081c8e2 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>  	u32 base = 0, pos = 0;
>  	bool visible;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
> +
>  	if (on)
>  		base = intel_crtc->cursor_addr;
>  
> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
>  
>  	if (dev_priv->info->gen >= 6)
>  		gen6_rps_idle(dev->dev_private);
> +
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_update(dev);
>  }
>  
> +
>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>  			struct intel_ring_buffer *ring)
>  {
>  	struct drm_device *dev = obj->base.dev;
>  	struct drm_crtc *crtc;
>  
> -	if (!i915.powersave)
> -		return;
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
>  
>  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>  		if (!crtc->fb)
> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
nav>  	if (work == NULL)
>  		return -ENOMEM;
>  
> +	/* Inactivate PSR early in page flip */
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
> +
>  	work->event = event;
>  	work->crtc = crtc;
>  	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 30d4350..e9a0ace 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static bool is_edp_psr(struct drm_device *dev)
> +static bool is_edp_psr(struct intel_dp *intel_dp)
> +{
> +	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
> +}
> +
> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> +	uint32_t val;
>  
> -	return dev_priv->psr.sink_support;
> +	val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
> +		VLV_EDP_PSR_CURR_STATE_MASK;
> +	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>  }
>  
>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> -	if (!HAS_PSR(dev))
> -		return false;
> +	if (HAS_PSR(dev)) {
> +		if (IS_VALLEYVIEW(dev))
> +			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
> +				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
> +		else
> +			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	}
>  
> -	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	return false;
>  }
>  
>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>  
>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct edp_vsc_psr psr_vsc;
> +	uint32_t val;
>  
>  	if (dev_priv->psr.setup_done)
>  		return;
>  
> -	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> -	memset(&psr_vsc, 0, sizeof(psr_vsc));
> -	psr_vsc.sdp_header.HB0 = 0;
> -	psr_vsc.sdp_header.HB1 = 0x7;
> -	psr_vsc.sdp_header.HB2 = 0x2;
> -	psr_vsc.sdp_header.HB3 = 0x8;
> -	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> +	if (IS_VALLEYVIEW(dev)) {
> +		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
> +		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> +		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> +		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
> +
> +		val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
> +		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> +		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> +		I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
> +	} else {
> +		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> +		memset(&psr_vsc, 0, sizeof(psr_vsc));
> +		psr_vsc.sdp_header.HB0 = 0;
> +		psr_vsc.sdp_header.HB1 = 0x7;
> +		psr_vsc.sdp_header.HB2 = 0x2;
> +		psr_vsc.sdp_header.HB3 = 0x8;
> +		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>  
> -	/* Avoid continuous PSR exit by masking memup and hpd */
> -	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> -		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> +		/* Avoid continuous PSR exit by masking memup and hpd */
> +		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> +			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> +	}
>  
>  	dev_priv->psr.setup_done = true;
>  }
>  
> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
> +{
> +	/* Enable PSR in sink */
> +	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> +				    DP_PSR_ENABLE);

Don't we want the same main-link poweroff logic as HSW? Or maybe we
should just keep the main link on always as long as we can't enter
the low power states w/ DPLL/pipe/port off.

Did you already figure out why that's not happening? Looking at the
PSRSTAT registers, my guess is that D0i1 is where we end up currently,
and that doesn't actually turn off anything but the planes (to stop
memory fetches). D0i2 would turn off everything.

But I guess we should anyway do this in steps. First getting the
current stuff in, then trying to get into D0i2 state, and finally
getting the display power well turned off when in PSR.

I think once we get to working on D0i2, we'll need to move the PSR
wakeup to happen from a workqueue since it essentially requires a
full modeset. Even now in your code it's somewhat questionable
since you're doing stuff like aux transfers while holding
struct_mutex.

> +}
> +
>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>  		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>  }
>  
> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
> +
> +	uint32_t idle_frames = 1;
> +	uint32_t val;
> +
> +	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));

I don't think we want to preserve anything here. We need to make sure
everything is initialized correctly rather than trusting some old junk
in the register.

> +	val |= VLV_EDP_PSR_ENABLE;
> +	val &= ~VLV_EDP_PSR_MODE_MASK;
> +
> +	val |= VLV_EDP_PSR_MODE_HW_TIMER;
> +	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
> +	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
> +
> +	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
> +}
> +
>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> -	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> -	    (dig_port->port != PORT_A)) {
> +	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> +			     (dig_port->port != PORT_A))) {
>  		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>  		return false;
>  	}
> @@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> +	/* Baytrail supports per-pipe PSR configuration, however PSR on
> +	* PIPE_B isn't working properly. So let's keep it disabled for now. */
> +	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
> +		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
> +		return false;
> +	}
> +
>  	dev_priv->psr.source_ok = true;
>  	return true;
>  }
>  
>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
>  
> -	if (!intel_edp_psr_match_conditions(intel_dp) ||
> -	    intel_edp_is_psr_enabled(dev))
> -		return;
> +	if (IS_VALLEYVIEW(dev)) {
> +		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
> +			return;
> +	} else
> +		if (intel_edp_is_psr_enabled(dev))
> +			return;
>  
>  	/* Setup PSR once */
>  	intel_edp_psr_setup(intel_dp);
>  
>  	/* Enable PSR on the panel */
> -	intel_edp_psr_enable_sink(intel_dp);
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_enable_sink(intel_dp);
> +	else
> +		intel_edp_psr_enable_sink(intel_dp);
>  
>  	/* Enable PSR on the host */
> -	intel_edp_psr_enable_source(intel_dp);
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_enable_source(intel_dp);
> +	else
> +		intel_edp_psr_enable_source(intel_dp);
> +
> +	dev_priv->psr.active = true;
>  }
>  
>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	if (!is_edp_psr(intel_dp))
> +		return;
>  
> -	if (intel_edp_psr_match_conditions(intel_dp) &&
> -	    !intel_edp_is_psr_enabled(dev))
> +	if (intel_edp_psr_match_conditions(intel_dp))
>  		intel_edp_psr_do_enable(intel_dp);
>  }
>  
> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
> +	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
> +
> +	if (!dev_priv->psr.setup_done)
> +		return;
> +
> +	intel_edp_psr_inactivate(dev);
> +
> +	if (val & VLV_EDP_PSR_IN_TRANS)
> +		udelay(250);

Might we want a warning if the bit doesn't go down in expected time?

> +
> +	val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
> +	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
> +	val &= ~VLV_EDP_PSR_ENABLE;
> +	val &= ~VLV_EDP_PSR_MODE_MASK;
> +	I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
> +}
> +
>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
>  {
>  	struct intel_encoder *encoder;
>  	struct intel_dp *intel_dp = NULL;
> +	struct intel_crtc *intel_crtc;
>  
>  	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>  		if (encoder->type == INTEL_OUTPUT_EDP) {
>  			intel_dp = enc_to_intel_dp(&encoder->base);
>  
> -			if (!is_edp_psr(dev))
> +			if (!is_edp_psr(intel_dp))
>  				return;
>  
> -			if (!intel_edp_psr_match_conditions(intel_dp))
> -				intel_edp_psr_disable(intel_dp);
> -			else
> +			intel_crtc = to_intel_crtc(encoder->base.crtc);
> +
> +			if (!intel_edp_psr_match_conditions(intel_dp)) {
> +				if (IS_VALLEYVIEW(dev))
> +					vlv_edp_psr_disable(intel_dp);
> +				else
> +					intel_edp_psr_disable(intel_dp);
> +			} else
>  				if (!intel_edp_is_psr_enabled(dev))
>  					intel_edp_psr_do_enable(intel_dp);
>  		}
>  }
>  
> +void intel_edp_psr_inactivate(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_encoder *encoder;
> +	struct intel_crtc *intel_crtc;
> +	struct intel_dp *intel_dp = NULL;
> +
> +	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
> +		return;
> +
> +	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
> +		if (encoder->type == INTEL_OUTPUT_EDP) {
> +			intel_dp = enc_to_intel_dp(&encoder->base);
> +			intel_crtc = to_intel_crtc(encoder->base.crtc);
> +
> +			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
> +							    intel_crtc->pipe))
> +				continue;
> +
> +			dev_priv->psr.active = false;
> +			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
> +				   VLV_EDP_PSR_RESET);
> +			/* WaClearPSRReset:vlv */
> +			I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
> +
> +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +		}
> +}
> +
>  static void intel_disable_dp(struct intel_encoder *encoder)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	enum port port = dp_to_dig_port(intel_dp)->port;
>  	struct drm_device *dev = encoder->base.dev;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_disable(intel_dp);
> +
>  	/* Make sure the panel is off before trying to change the mode. But also
>  	 * ensure that we have vdd while we switch off the panel. */
>  	intel_edp_backlight_off(intel_dp);
> @@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
>  	intel_edp_backlight_on(intel_dp);
> +	intel_edp_psr_enable(intel_dp);
>  }
>  
>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 71c1371..82026ef 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>  void intel_edp_psr_update(struct drm_device *dev);
> +void intel_edp_psr_inactivate(struct drm_device *dev);
>  
>  
>  /* intel_dsi.c */
> -- 
> 1.8.1.2

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:56               ` Ville Syrjälä
@ 2014-01-29 15:47                 ` Rodrigo Vivi
  2014-01-29 16:38                   ` Ville Syrjälä
  2014-01-29 15:50                 ` Rodrigo Vivi
  2014-02-12 16:29                 ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 15:47 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 12:56 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> This patch adds PSR Support to Baytrail.
>>
>> Baytrail cannot easily detect screen updates and force PSR exit.
>> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> and update to enable it back on next display mark_idle.
>>
>> v2: Also inactivate PSR on cursor update.
>> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>>     early on page flip besides avoid initializing inactive/active flag
>>     more than once.
>> v4: Fix identation issues.
>> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>>     support disabled by for now since it isn't working properly yet.
>> v6: Removing forgotten comment and useless clkgating definition.
>>
>> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
>> ---
>>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
>>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
>>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
>>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
>>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
>>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
>>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>>  7 files changed, 267 insertions(+), 39 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> index 4b852c6..c28de65 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>>       struct drm_device *dev = node->minor->dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       u32 psrperf = 0;
>> +     u32 statA = 0;
>> +     u32 statB = 0;
>>       bool enabled = false;
>>
>>       intel_runtime_pm_get(dev_priv);
>> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>>
>> -     enabled = HAS_PSR(dev) &&
>> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
>> +     if (HAS_PSR(dev)) {
>> +             if (IS_VALLEYVIEW(dev)) {
>> +                     statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
>> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> +                     statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
>> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
>> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
>> +             } else
>> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     }
>> +     seq_printf(m, "Enabled: %s", yesno(enabled));
>>
>> -     if (HAS_PSR(dev))
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> +                     seq_puts(m, " pipe A");
>> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> +                     seq_puts(m, " pipe B");
>> +     }
>> +
>> +     seq_puts(m, "\n");
>> +
>> +     /* VLV PSR has no kind of performance counter */
>> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>>                       EDP_PSR_PERF_CNT_MASK;
>> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> +     }
>>
>>       intel_runtime_pm_put(dev_priv);
>>       return 0;
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> index 7c53d4d..34dee24 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -747,6 +747,7 @@ struct i915_psr {
>>       bool sink_support;
>>       bool source_ok;
>>       bool setup_done;
>> +     bool active;
>>  };
>>
>>  enum intel_pch {
>> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
>>
>>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
>>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
>> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
>> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
>> +                              IS_VALLEYVIEW(dev))
>>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
>>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
>>
>> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>> index 39770f7..01137fe 100644
>> --- a/drivers/gpu/drm/i915/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>>               goto unlock;
>>       }
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>> +
>>       /* Try to flush the object off the GPU without holding the lock.
>>        * We will repeat the flush holding the lock in the normal manner
>>        * to catch cases where we are gazumped.
>> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>>       if (ret)
>>               return ret;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>> +
>>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>>       if (&obj->base == NULL) {
>>               ret = -ENOENT;
>> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>>       if (ret)
>>               return ret;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>
> The locking for PSR seems to be as fubar as for FBC. Also the front
> buffer tracking is missing, but I guess I need to make that work for FBC
> first, and then we need to figure out how to tie it in w/ PSR.
>

agree... I'll wait your fbc work.

>> +
>>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>>       if (&obj->base == NULL) {
>>               ret = -ENOENT;
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> index cbbaf26..2039d71 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -1968,6 +1968,43 @@
>>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>>
>> +/* VLV eDP PSR registers */
>> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
>> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
>> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
>> +#define  VLV_EDP_PSR_RESET                   (1<<1)
>> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
>> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
>> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
>> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
>> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
>> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
>> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
>> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
>> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
>> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
>> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
>
> Can we just name the PSR registers like in the spec? Eg. just
> VLV_PSRCTL(). Would make it easier to compare things w/ the spec.
>

Done.

>> +
>> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
>> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
>> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
>> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
>> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
>> +#define VLV_EDP_VSC_SDP_REG(pipe)    _PIPE(pipe, _VSCSDPA, _VSCSDPB)
>> +
>> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
>> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
>> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
>> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
>> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
>> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
>> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
>> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
>> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
>> +#define  VLV_EDP_PSR_EXIT            (5<<0)
>> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
>> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
>> +
>>  /* HSW+ eDP PSR registers */
>>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> index 1a9aa19..081c8e2 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>>       u32 base = 0, pos = 0;
>>       bool visible;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>> +
>>       if (on)
>>               base = intel_crtc->cursor_addr;
>>
>> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
>>
>>       if (dev_priv->info->gen >= 6)
>>               gen6_rps_idle(dev->dev_private);
>> +
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_update(dev);
>>  }
>>
>> +
>>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>>                       struct intel_ring_buffer *ring)
>>  {
>>       struct drm_device *dev = obj->base.dev;
>>       struct drm_crtc *crtc;
>>
>> -     if (!i915.powersave)
>> -             return;
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>>
>>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>>               if (!crtc->fb)
>> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> nav>    if (work == NULL)

sorry, I didn't get this..
what did you mean?

>>               return -ENOMEM;
>>
>> +     /* Inactivate PSR early in page flip */
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>> +
>>       work->event = event;
>>       work->crtc = crtc;
>>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> index 30d4350..e9a0ace 100644
>> --- a/drivers/gpu/drm/i915/intel_dp.c
>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>>       }
>>  }
>>
>> -static bool is_edp_psr(struct drm_device *dev)
>> +static bool is_edp_psr(struct intel_dp *intel_dp)
>> +{
>> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>> +}
>> +
>> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>>  {
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>> +     uint32_t val;
>>
>> -     return dev_priv->psr.sink_support;
>> +     val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
>> +             VLV_EDP_PSR_CURR_STATE_MASK;
>> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>>  }
>>
>>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>>  {
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>
>> -     if (!HAS_PSR(dev))
>> -             return false;
>> +     if (HAS_PSR(dev)) {
>> +             if (IS_VALLEYVIEW(dev))
>> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
>> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
>> +             else
>> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     }
>>
>> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     return false;
>>  }
>>
>>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>>
>>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>>  {
>> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct edp_vsc_psr psr_vsc;
>> +     uint32_t val;
>>
>>       if (dev_priv->psr.setup_done)
>>               return;
>>
>> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
>> -     psr_vsc.sdp_header.HB0 = 0;
>> -     psr_vsc.sdp_header.HB1 = 0x7;
>> -     psr_vsc.sdp_header.HB2 = 0x2;
>> -     psr_vsc.sdp_header.HB3 = 0x8;
>> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
>> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
>> +
>> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
>> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
>> +     } else {
>> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
>> +             psr_vsc.sdp_header.HB0 = 0;
>> +             psr_vsc.sdp_header.HB1 = 0x7;
>> +             psr_vsc.sdp_header.HB2 = 0x2;
>> +             psr_vsc.sdp_header.HB3 = 0x8;
>> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>>
>> -     /* Avoid continuous PSR exit by masking memup and hpd */
>> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> +             /* Avoid continuous PSR exit by masking memup and hpd */
>> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> +     }
>>
>>       dev_priv->psr.setup_done = true;
>>  }
>>
>> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> +{
>> +     /* Enable PSR in sink */
>> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
>> +                                 DP_PSR_ENABLE);
>
> Don't we want the same main-link poweroff logic as HSW?


I can't remember why I'm not disabling main link here... So I did a
quickly try now and failure on tests was huge... so let's keep it
simple for now ;)

> Or maybe we
> should just keep the main link on always as long as we can't enter
> the low power states w/ DPLL/pipe/port off.
>
> Did you already figure out why that's not happening? Looking at the
> PSRSTAT registers, my guess is that D0i1 is where we end up currently,
> and that doesn't actually turn off anything but the planes (to stop
> memory fetches). D0i2 would turn off everything.

no idea.. :(

> But I guess we should anyway do this in steps. First getting the
> current stuff in, then trying to get into D0i2 state, and finally
> getting the display power well turned off when in PSR.

Agree.

>
> I think once we get to working on D0i2, we'll need to move the PSR
> wakeup to happen from a workqueue since it essentially requires a
> full modeset. Even now in your code it's somewhat questionable
> since you're doing stuff like aux transfers while holding
> struct_mutex.

uhm... anything we should try now to improve?

>
>> +}
>> +
>>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>>  }
>>
>> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
>> +{
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> +
>> +     uint32_t idle_frames = 1;
>> +     uint32_t val;
>> +
>> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>
> I don't think we want to preserve anything here. We need to make sure
> everything is initialized correctly rather than trusting some old junk
> in the register.

Done.

>
>> +     val |= VLV_EDP_PSR_ENABLE;
>> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> +
>> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
>> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
>> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
>> +
>> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> +}
>> +
>>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>>               return false;
>>       }
>>
>> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> -         (dig_port->port != PORT_A)) {
>> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> +                          (dig_port->port != PORT_A))) {
>>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>>               return false;
>>       }
>> @@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>>               return false;
>>       }
>>
>> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
>> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
>> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
>> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
>> +             return false;
>> +     }
>> +
>>       dev_priv->psr.source_ok = true;
>>       return true;
>>  }
>>
>>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>>  {
>> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>>
>> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
>> -         intel_edp_is_psr_enabled(dev))
>> -             return;
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
>> +                     return;
>> +     } else
>> +             if (intel_edp_is_psr_enabled(dev))
>> +                     return;
>>
>>       /* Setup PSR once */
>>       intel_edp_psr_setup(intel_dp);
>>
>>       /* Enable PSR on the panel */
>> -     intel_edp_psr_enable_sink(intel_dp);
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_enable_sink(intel_dp);
>> +     else
>> +             intel_edp_psr_enable_sink(intel_dp);
>>
>>       /* Enable PSR on the host */
>> -     intel_edp_psr_enable_source(intel_dp);
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_enable_source(intel_dp);
>> +     else
>> +             intel_edp_psr_enable_source(intel_dp);
>> +
>> +     dev_priv->psr.active = true;
>>  }
>>
>>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
>>  {
>> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> +     if (!is_edp_psr(intel_dp))
>> +             return;
>>
>> -     if (intel_edp_psr_match_conditions(intel_dp) &&
>> -         !intel_edp_is_psr_enabled(dev))
>> +     if (intel_edp_psr_match_conditions(intel_dp))
>>               intel_edp_psr_do_enable(intel_dp);
>>  }
>>
>> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
>> +{
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> +     uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
>> +
>> +     if (!dev_priv->psr.setup_done)
>> +             return;
>> +
>> +     intel_edp_psr_inactivate(dev);
>> +
>> +     if (val & VLV_EDP_PSR_IN_TRANS)
>> +             udelay(250);
>
> Might we want a warning if the bit doesn't go down in expected time?

Done.

>
>> +
>> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
>> +     val &= ~VLV_EDP_PSR_ENABLE;
>> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> +}
>> +
>>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
>>  {
>>       struct intel_encoder *encoder;
>>       struct intel_dp *intel_dp = NULL;
>> +     struct intel_crtc *intel_crtc;
>>
>>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>>               if (encoder->type == INTEL_OUTPUT_EDP) {
>>                       intel_dp = enc_to_intel_dp(&encoder->base);
>>
>> -                     if (!is_edp_psr(dev))
>> +                     if (!is_edp_psr(intel_dp))
>>                               return;
>>
>> -                     if (!intel_edp_psr_match_conditions(intel_dp))
>> -                             intel_edp_psr_disable(intel_dp);
>> -                     else
>> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> +
>> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
>> +                             if (IS_VALLEYVIEW(dev))
>> +                                     vlv_edp_psr_disable(intel_dp);
>> +                             else
>> +                                     intel_edp_psr_disable(intel_dp);
>> +                     } else
>>                               if (!intel_edp_is_psr_enabled(dev))
>>                                       intel_edp_psr_do_enable(intel_dp);
>>               }
>>  }
>>
>> +void intel_edp_psr_inactivate(struct drm_device *dev)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_encoder *encoder;
>> +     struct intel_crtc *intel_crtc;
>> +     struct intel_dp *intel_dp = NULL;
>> +
>> +     if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
>> +             return;
>> +
>> +     list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>> +             if (encoder->type == INTEL_OUTPUT_EDP) {
>> +                     intel_dp = enc_to_intel_dp(&encoder->base);
>> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> +
>> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
>> +                                                         intel_crtc->pipe))
>> +                             continue;
>> +
>> +                     dev_priv->psr.active = false;
>> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
>> +                                VLV_EDP_PSR_RESET);
>> +                     /* WaClearPSRReset:vlv */
>> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
>> +
>> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>> +             }
>> +}
>> +
>>  static void intel_disable_dp(struct intel_encoder *encoder)
>>  {
>>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>       enum port port = dp_to_dig_port(intel_dp)->port;
>>       struct drm_device *dev = encoder->base.dev;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_disable(intel_dp);
>> +
>>       /* Make sure the panel is off before trying to change the mode. But also
>>        * ensure that we have vdd while we switch off the panel. */
>>       intel_edp_backlight_off(intel_dp);
>> @@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>
>>       intel_edp_backlight_on(intel_dp);
>> +     intel_edp_psr_enable(intel_dp);
>>  }
>>
>>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index 71c1371..82026ef 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>>  void intel_edp_psr_update(struct drm_device *dev);
>> +void intel_edp_psr_inactivate(struct drm_device *dev);
>>
>>
>>  /* intel_dsi.c */
>> --
>> 1.8.1.2
>
> --
> Ville Syrjälä
> Intel OTC

Thank you very much!

-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:56               ` Ville Syrjälä
  2014-01-29 15:47                 ` Rodrigo Vivi
@ 2014-01-29 15:50                 ` Rodrigo Vivi
  2014-01-30 13:02                   ` Chris Wilson
  2014-02-12 16:29                 ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 15:50 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, sw_finish and mark_busy}
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.
v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
    support disabled by for now since it isn't working properly yet.
v6: Removing forgotten comment and useless clkgating definition.
v7: Remove inactivate from set_domain. Chris warned this was semanticaly
    wrong.
v8: Accept Ville's suggestions: Use register's names matching spec and
    warn if transition took longer than it should.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   6 ++
 drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
 drivers/gpu/drm/i915/intel_display.c |  14 +++
 drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 7 files changed, 265 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index bc8707f..2949c48 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 statA = 0;
+	u32 statB = 0;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "Enabled: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			statA = I915_READ(VLV_PSRSTAT(PIPE_A)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			statB = I915_READ(VLV_PSRSTAT(PIPE_B)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
+	seq_printf(m, "Enabled: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (IS_VALLEYVIEW(dev)) {
+		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe A");
+		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe B");
+	}
+
+	seq_puts(m, "\n");
+
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7c53d4d..34dee24 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,6 +747,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 };
 
 enum intel_pch {
@@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39770f7..b3eec3b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1299,6 +1299,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4059,6 +4062,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cbbaf26..a5815d0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1968,6 +1968,43 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_VSCSDP(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a9aa19..a08e3ce 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8228,14 +8231,21 @@ void intel_mark_idle(struct drm_device *dev)
 
 	if (dev_priv->info->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	if (!i915.powersave)
 		return;
 
@@ -8688,6 +8698,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 30d4350..5dae2af 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
-static bool is_edp_psr(struct drm_device *dev)
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	return dev_priv->psr.sink_support;
+	val = I915_READ(VLV_PSRSTAT(pipe)) &
+		VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev))
+			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
+				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
+		else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
 
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_VSCSDP(PIPE_A));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_VSCSDP(PIPE_A), val);
+
+		val  = I915_READ(VLV_VSCSDP(PIPE_B));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_VSCSDP(PIPE_B), val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1678,6 +1713,27 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+
+	uint32_t idle_frames = 1;
+	uint32_t val = 0;
+
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1719,8 +1775,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1765,37 +1821,84 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	/* Baytrail supports per-pipe PSR configuration, however PSR on
+	* PIPE_B isn't working properly. So let's keep it disabled for now. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
+		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
+		return false;
+	}
+
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
+	if (IS_VALLEYVIEW(dev)) {
+		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
+			return;
+	} else
+		if (intel_edp_is_psr_enabled(dev))
+			return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	if (!is_edp_psr(intel_dp))
+		return;
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
+	if (intel_edp_psr_match_conditions(intel_dp))
 		intel_edp_psr_do_enable(intel_dp);
 }
 
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val;
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
+		      VLV_EDP_PSR_IN_TRANS) == 0, 250))
+		WARN(1, "PSR transition took longer than expected\n");
+
+	val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+}
+
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
 {
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
+	struct intel_crtc *intel_crtc;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
 
-			if (!is_edp_psr(dev))
+			if (!is_edp_psr(intel_dp))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_crtc *intel_crtc;
+	struct intel_dp *intel_dp = NULL;
+
+	if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
+							    intel_crtc->pipe))
+				continue;
+
+			dev_priv->psr.active = false;
+			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe),
+				   VLV_EDP_PSR_RESET);
+			/* WaClearPSRReset:vlv */
+			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_backlight_off(intel_dp);
@@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 71c1371..82026ef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 15:47                 ` Rodrigo Vivi
@ 2014-01-29 16:38                   ` Ville Syrjälä
  2014-01-29 17:48                     ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-29 16:38 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 01:47:00PM -0200, Rodrigo Vivi wrote:
> On Wed, Jan 29, 2014 at 12:56 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> >> This patch adds PSR Support to Baytrail.
> >>
> >> Baytrail cannot easily detect screen updates and force PSR exit.
> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> >> and update to enable it back on next display mark_idle.
> >>
> >> v2: Also inactivate PSR on cursor update.
> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >>     early on page flip besides avoid initializing inactive/active flag
> >>     more than once.
> >> v4: Fix identation issues.
> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >>     support disabled by for now since it isn't working properly yet.
> >> v6: Removing forgotten comment and useless clkgating definition.
> >>
> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> >> ---
> >>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
> >>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
> >>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
> >>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
> >>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
> >>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
> >>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
> >>  7 files changed, 267 insertions(+), 39 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >> index 4b852c6..c28de65 100644
> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >>       struct drm_device *dev = node->minor->dev;
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>       u32 psrperf = 0;
> >> +     u32 statA = 0;
> >> +     u32 statB = 0;
> >>       bool enabled = false;
> >>
> >>       intel_runtime_pm_get(dev_priv);
> >> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
> >>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
> >>
> >> -     enabled = HAS_PSR(dev) &&
> >> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
> >> +     if (HAS_PSR(dev)) {
> >> +             if (IS_VALLEYVIEW(dev)) {
> >> +                     statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +                     statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
> >> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
> >> +             } else
> >> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     }
> >> +     seq_printf(m, "Enabled: %s", yesno(enabled));
> >>
> >> -     if (HAS_PSR(dev))
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> +                     seq_puts(m, " pipe A");
> >> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> +                     seq_puts(m, " pipe B");
> >> +     }
> >> +
> >> +     seq_puts(m, "\n");
> >> +
> >> +     /* VLV PSR has no kind of performance counter */
> >> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
> >>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
> >>                       EDP_PSR_PERF_CNT_MASK;
> >> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> +     }
> >>
> >>       intel_runtime_pm_put(dev_priv);
> >>       return 0;
> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> >> index 7c53d4d..34dee24 100644
> >> --- a/drivers/gpu/drm/i915/i915_drv.h
> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
> >> @@ -747,6 +747,7 @@ struct i915_psr {
> >>       bool sink_support;
> >>       bool source_ok;
> >>       bool setup_done;
> >> +     bool active;
> >>  };
> >>
> >>  enum intel_pch {
> >> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
> >>
> >>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
> >>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
> >> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
> >> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
> >> +                              IS_VALLEYVIEW(dev))
> >>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
> >>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> >> index 39770f7..01137fe 100644
> >> --- a/drivers/gpu/drm/i915/i915_gem.c
> >> +++ b/drivers/gpu/drm/i915/i915_gem.c
> >> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
> >>               goto unlock;
> >>       }
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >> +
> >>       /* Try to flush the object off the GPU without holding the lock.
> >>        * We will repeat the flush holding the lock in the normal manner
> >>        * to catch cases where we are gazumped.
> >> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
> >>       if (ret)
> >>               return ret;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >> +
> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >>       if (&obj->base == NULL) {
> >>               ret = -ENOENT;
> >> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
> >>       if (ret)
> >>               return ret;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >
> > The locking for PSR seems to be as fubar as for FBC. Also the front
> > buffer tracking is missing, but I guess I need to make that work for FBC
> > first, and then we need to figure out how to tie it in w/ PSR.
> >
> 
> agree... I'll wait your fbc work.
> 
> >> +
> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >>       if (&obj->base == NULL) {
> >>               ret = -ENOENT;
> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> >> index cbbaf26..2039d71 100644
> >> --- a/drivers/gpu/drm/i915/i915_reg.h
> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
> >> @@ -1968,6 +1968,43 @@
> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
> >>
> >> +/* VLV eDP PSR registers */
> >> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
> >> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
> >> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
> >> +#define  VLV_EDP_PSR_RESET                   (1<<1)
> >> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
> >> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
> >> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
> >> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
> >> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
> >> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
> >> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
> >> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
> >> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
> >> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
> >> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
> >
> > Can we just name the PSR registers like in the spec? Eg. just
> > VLV_PSRCTL(). Would make it easier to compare things w/ the spec.
> >
> 
> Done.
> 
> >> +
> >> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
> >> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
> >> +#define VLV_EDP_VSC_SDP_REG(pipe)    _PIPE(pipe, _VSCSDPA, _VSCSDPB)
> >> +
> >> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
> >> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
> >> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
> >> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
> >> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
> >> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
> >> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
> >> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
> >> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
> >> +#define  VLV_EDP_PSR_EXIT            (5<<0)
> >> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
> >> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
> >> +
> >>  /* HSW+ eDP PSR registers */
> >>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
> >>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> >> index 1a9aa19..081c8e2 100644
> >> --- a/drivers/gpu/drm/i915/intel_display.c
> >> +++ b/drivers/gpu/drm/i915/intel_display.c
> >> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >>       u32 base = 0, pos = 0;
> >>       bool visible;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >> +
> >>       if (on)
> >>               base = intel_crtc->cursor_addr;
> >>
> >> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
> >>
> >>       if (dev_priv->info->gen >= 6)
> >>               gen6_rps_idle(dev->dev_private);
> >> +
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_update(dev);
> >>  }
> >>
> >> +
> >>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
> >>                       struct intel_ring_buffer *ring)
> >>  {
> >>       struct drm_device *dev = obj->base.dev;
> >>       struct drm_crtc *crtc;
> >>
> >> -     if (!i915.powersave)
> >> -             return;
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >>
> >>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >>               if (!crtc->fb)
> >> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> > nav>    if (work == NULL)
> 
> sorry, I didn't get this..
> what did you mean?

Nothing. Just managed to misplace a few characters here I guess. I blame
vim :)

> 
> >>               return -ENOMEM;
> >>
> >> +     /* Inactivate PSR early in page flip */
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >> +
> >>       work->event = event;
> >>       work->crtc = crtc;
> >>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> >> index 30d4350..e9a0ace 100644
> >> --- a/drivers/gpu/drm/i915/intel_dp.c
> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
> >> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> >>       }
> >>  }
> >>
> >> -static bool is_edp_psr(struct drm_device *dev)
> >> +static bool is_edp_psr(struct intel_dp *intel_dp)
> >> +{
> >> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
> >> +}
> >> +
> >> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
> >>  {
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     uint32_t val;
> >>
> >> -     return dev_priv->psr.sink_support;
> >> +     val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
> >> +             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
> >>  }
> >>
> >>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
> >>  {
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>
> >> -     if (!HAS_PSR(dev))
> >> -             return false;
> >> +     if (HAS_PSR(dev)) {
> >> +             if (IS_VALLEYVIEW(dev))
> >> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
> >> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
> >> +             else
> >> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     }
> >>
> >> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     return false;
> >>  }
> >>
> >>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >>
> >>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
> >>  {
> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>       struct edp_vsc_psr psr_vsc;
> >> +     uint32_t val;
> >>
> >>       if (dev_priv->psr.setup_done)
> >>               return;
> >>
> >> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> -     psr_vsc.sdp_header.HB0 = 0;
> >> -     psr_vsc.sdp_header.HB1 = 0x7;
> >> -     psr_vsc.sdp_header.HB2 = 0x2;
> >> -     psr_vsc.sdp_header.HB3 = 0x8;
> >> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
> >> +
> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
> >> +     } else {
> >> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> +             psr_vsc.sdp_header.HB0 = 0;
> >> +             psr_vsc.sdp_header.HB1 = 0x7;
> >> +             psr_vsc.sdp_header.HB2 = 0x2;
> >> +             psr_vsc.sdp_header.HB3 = 0x8;
> >> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >>
> >> -     /* Avoid continuous PSR exit by masking memup and hpd */
> >> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> +             /* Avoid continuous PSR exit by masking memup and hpd */
> >> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> +     }
> >>
> >>       dev_priv->psr.setup_done = true;
> >>  }
> >>
> >> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >> +{
> >> +     /* Enable PSR in sink */
> >> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> >> +                                 DP_PSR_ENABLE);
> >
> > Don't we want the same main-link poweroff logic as HSW?
> 
> 
> I can't remember why I'm not disabling main link here... So I did a
> quickly try now and failure on tests was huge... so let's keep it
> simple for now ;)

I think you are disabling the main link currently. Or at least you're
telling the sink that main link is going to be turned off, and you also
leave the VLV_EDP_PSR_SRC_TRANSMITTER_STATE bit unset, so I think that
should make the main link turn off. Well, since the pipe and port remain
active, I don't know if the link actually turns off.

I would assume that if you don't turn off the link, it would be easier
to keep things happy. A bit weird that you had the opposite result.

BTW now that I look at the HSW code, it seems buggy. When the sink
doesn't require link training, we tell it that we're going to turn the
link off, otherwise we tell it link will be on. But then we actually do
the opposite in intel_edp_psr_enable_source().

> 
> > Or maybe we
> > should just keep the main link on always as long as we can't enter
> > the low power states w/ DPLL/pipe/port off.
> >
> > Did you already figure out why that's not happening? Looking at the
> > PSRSTAT registers, my guess is that D0i1 is where we end up currently,
> > and that doesn't actually turn off anything but the planes (to stop
> > memory fetches). D0i2 would turn off everything.
> 
> no idea.. :(

Did you check the status bit BTW? Does it say D0i1 or D0i2 when you're
in PSR?

> 
> > But I guess we should anyway do this in steps. First getting the
> > current stuff in, then trying to get into D0i2 state, and finally
> > getting the display power well turned off when in PSR.
> 
> Agree.
> 
> >
> > I think once we get to working on D0i2, we'll need to move the PSR
> > wakeup to happen from a workqueue since it essentially requires a
> > full modeset. Even now in your code it's somewhat questionable
> > since you're doing stuff like aux transfers while holding
> > struct_mutex.
> 
> uhm... anything we should try now to improve?

Hmm. We already seem to do some PSR setup while holding struct_mutex,
but we don't hold it always. Although I think w/ HSW we end up
protecting the PSR state w/ the modeset locks since we only fiddle
with it during modesets. So for HSW we should just move the PSR update
call in set_base outside struct_mutex.

But then for VLV, you want to call it from various places that already
hold struct_mutex, so it's getting messy. Just moving it to a workqueue
would seem like the easiest option here, and then you could grab the
modeset locks in the work function.

> 
> >
> >> +}
> >> +
> >>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
> >>  }
> >>
> >> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
> >> +{
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >> +
> >> +     uint32_t idle_frames = 1;
> >> +     uint32_t val;
> >> +
> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
> >
> > I don't think we want to preserve anything here. We need to make sure
> > everything is initialized correctly rather than trusting some old junk
> > in the register.
> 
> Done.
> 
> >
> >> +     val |= VLV_EDP_PSR_ENABLE;
> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
> >> +
> >> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
> >> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
> >> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
> >> +
> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
> >> +}
> >> +
> >>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >>               return false;
> >>       }
> >>
> >> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> >> -         (dig_port->port != PORT_A)) {
> >> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> >> +                          (dig_port->port != PORT_A))) {
> >>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
> >>               return false;
> >>       }
> >> @@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >>               return false;
> >>       }
> >>
> >> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
> >> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
> >> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
> >> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
> >> +             return false;
> >> +     }
> >> +
> >>       dev_priv->psr.source_ok = true;
> >>       return true;
> >>  }
> >>
> >>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
> >>  {
> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >>
> >> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
> >> -         intel_edp_is_psr_enabled(dev))
> >> -             return;
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
> >> +                     return;
> >> +     } else
> >> +             if (intel_edp_is_psr_enabled(dev))
> >> +                     return;
> >>
> >>       /* Setup PSR once */
> >>       intel_edp_psr_setup(intel_dp);
> >>
> >>       /* Enable PSR on the panel */
> >> -     intel_edp_psr_enable_sink(intel_dp);
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_enable_sink(intel_dp);
> >> +     else
> >> +             intel_edp_psr_enable_sink(intel_dp);
> >>
> >>       /* Enable PSR on the host */
> >> -     intel_edp_psr_enable_source(intel_dp);
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_enable_source(intel_dp);
> >> +     else
> >> +             intel_edp_psr_enable_source(intel_dp);
> >> +
> >> +     dev_priv->psr.active = true;
> >>  }
> >>
> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
> >>  {
> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> +     if (!is_edp_psr(intel_dp))
> >> +             return;
> >>
> >> -     if (intel_edp_psr_match_conditions(intel_dp) &&
> >> -         !intel_edp_is_psr_enabled(dev))
> >> +     if (intel_edp_psr_match_conditions(intel_dp))
> >>               intel_edp_psr_do_enable(intel_dp);
> >>  }
> >>
> >> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
> >> +{
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >> +     uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
> >> +
> >> +     if (!dev_priv->psr.setup_done)
> >> +             return;
> >> +
> >> +     intel_edp_psr_inactivate(dev);
> >> +
> >> +     if (val & VLV_EDP_PSR_IN_TRANS)
> >> +             udelay(250);
> >
> > Might we want a warning if the bit doesn't go down in expected time?
> 
> Done.
> 
> >
> >> +
> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
> >> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
> >> +     val &= ~VLV_EDP_PSR_ENABLE;
> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
> >> +}
> >> +
> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
> >>  {
> >>       struct intel_encoder *encoder;
> >>       struct intel_dp *intel_dp = NULL;
> >> +     struct intel_crtc *intel_crtc;
> >>
> >>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
> >>               if (encoder->type == INTEL_OUTPUT_EDP) {
> >>                       intel_dp = enc_to_intel_dp(&encoder->base);
> >>
> >> -                     if (!is_edp_psr(dev))
> >> +                     if (!is_edp_psr(intel_dp))
> >>                               return;
> >>
> >> -                     if (!intel_edp_psr_match_conditions(intel_dp))
> >> -                             intel_edp_psr_disable(intel_dp);
> >> -                     else
> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
> >> +
> >> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
> >> +                             if (IS_VALLEYVIEW(dev))
> >> +                                     vlv_edp_psr_disable(intel_dp);
> >> +                             else
> >> +                                     intel_edp_psr_disable(intel_dp);
> >> +                     } else
> >>                               if (!intel_edp_is_psr_enabled(dev))
> >>                                       intel_edp_psr_do_enable(intel_dp);
> >>               }
> >>  }
> >>
> >> +void intel_edp_psr_inactivate(struct drm_device *dev)
> >> +{
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_encoder *encoder;
> >> +     struct intel_crtc *intel_crtc;
> >> +     struct intel_dp *intel_dp = NULL;
> >> +
> >> +     if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
> >> +             return;
> >> +
> >> +     list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
> >> +             if (encoder->type == INTEL_OUTPUT_EDP) {
> >> +                     intel_dp = enc_to_intel_dp(&encoder->base);
> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
> >> +
> >> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
> >> +                                                         intel_crtc->pipe))
> >> +                             continue;
> >> +
> >> +                     dev_priv->psr.active = false;
> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
> >> +                                VLV_EDP_PSR_RESET);
> >> +                     /* WaClearPSRReset:vlv */
> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
> >> +
> >> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >> +             }
> >> +}
> >> +
> >>  static void intel_disable_dp(struct intel_encoder *encoder)
> >>  {
> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >>       enum port port = dp_to_dig_port(intel_dp)->port;
> >>       struct drm_device *dev = encoder->base.dev;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_disable(intel_dp);
> >> +
> >>       /* Make sure the panel is off before trying to change the mode. But also
> >>        * ensure that we have vdd while we switch off the panel. */
> >>       intel_edp_backlight_off(intel_dp);
> >> @@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >>
> >>       intel_edp_backlight_on(intel_dp);
> >> +     intel_edp_psr_enable(intel_dp);
> >>  }
> >>
> >>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> >> index 71c1371..82026ef 100644
> >> --- a/drivers/gpu/drm/i915/intel_drv.h
> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> >> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_update(struct drm_device *dev);
> >> +void intel_edp_psr_inactivate(struct drm_device *dev);
> >>
> >>
> >>  /* intel_dsi.c */
> >> --
> >> 1.8.1.2
> >
> > --
> > Ville Syrjälä
> > Intel OTC
> 
> Thank you very much!
> 
> -- 
> Rodrigo Vivi
> Blog: http://blog.vivi.eng.br

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 16:38                   ` Ville Syrjälä
@ 2014-01-29 17:48                     ` Rodrigo Vivi
  2014-01-29 18:24                       ` Ville Syrjälä
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-29 17:48 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 2:38 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Wed, Jan 29, 2014 at 01:47:00PM -0200, Rodrigo Vivi wrote:
>> On Wed, Jan 29, 2014 at 12:56 PM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> >> This patch adds PSR Support to Baytrail.
>> >>
>> >> Baytrail cannot easily detect screen updates and force PSR exit.
>> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> >> and update to enable it back on next display mark_idle.
>> >>
>> >> v2: Also inactivate PSR on cursor update.
>> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>> >>     early on page flip besides avoid initializing inactive/active flag
>> >>     more than once.
>> >> v4: Fix identation issues.
>> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>> >>     support disabled by for now since it isn't working properly yet.
>> >> v6: Removing forgotten comment and useless clkgating definition.
>> >>
>> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
>> >> ---
>> >>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
>> >>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
>> >>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
>> >>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
>> >>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
>> >>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
>> >>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>> >>  7 files changed, 267 insertions(+), 39 deletions(-)
>> >>
>> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> >> index 4b852c6..c28de65 100644
>> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> >> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>> >>       struct drm_device *dev = node->minor->dev;
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>       u32 psrperf = 0;
>> >> +     u32 statA = 0;
>> >> +     u32 statB = 0;
>> >>       bool enabled = false;
>> >>
>> >>       intel_runtime_pm_get(dev_priv);
>> >> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>> >>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>> >>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>> >>
>> >> -     enabled = HAS_PSR(dev) &&
>> >> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
>> >> +     if (HAS_PSR(dev)) {
>> >> +             if (IS_VALLEYVIEW(dev)) {
>> >> +                     statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
>> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +                     statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
>> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
>> >> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
>> >> +             } else
>> >> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     }
>> >> +     seq_printf(m, "Enabled: %s", yesno(enabled));
>> >>
>> >> -     if (HAS_PSR(dev))
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> >> +                     seq_puts(m, " pipe A");
>> >> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> >> +                     seq_puts(m, " pipe B");
>> >> +     }
>> >> +
>> >> +     seq_puts(m, "\n");
>> >> +
>> >> +     /* VLV PSR has no kind of performance counter */
>> >> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>> >>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>> >>                       EDP_PSR_PERF_CNT_MASK;
>> >> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> >> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> >> +     }
>> >>
>> >>       intel_runtime_pm_put(dev_priv);
>> >>       return 0;
>> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> >> index 7c53d4d..34dee24 100644
>> >> --- a/drivers/gpu/drm/i915/i915_drv.h
>> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> >> @@ -747,6 +747,7 @@ struct i915_psr {
>> >>       bool sink_support;
>> >>       bool source_ok;
>> >>       bool setup_done;
>> >> +     bool active;
>> >>  };
>> >>
>> >>  enum intel_pch {
>> >> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
>> >>
>> >>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
>> >>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
>> >> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
>> >> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
>> >> +                              IS_VALLEYVIEW(dev))
>> >>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
>> >>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
>> >>
>> >> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>> >> index 39770f7..01137fe 100644
>> >> --- a/drivers/gpu/drm/i915/i915_gem.c
>> >> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> >> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>> >>               goto unlock;
>> >>       }
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       /* Try to flush the object off the GPU without holding the lock.
>> >>        * We will repeat the flush holding the lock in the normal manner
>> >>        * to catch cases where we are gazumped.
>> >> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>> >>       if (ret)
>> >>               return ret;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>> >>       if (&obj->base == NULL) {
>> >>               ret = -ENOENT;
>> >> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>> >>       if (ret)
>> >>               return ret;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >
>> > The locking for PSR seems to be as fubar as for FBC. Also the front
>> > buffer tracking is missing, but I guess I need to make that work for FBC
>> > first, and then we need to figure out how to tie it in w/ PSR.
>> >
>>
>> agree... I'll wait your fbc work.
>>
>> >> +
>> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>> >>       if (&obj->base == NULL) {
>> >>               ret = -ENOENT;
>> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> >> index cbbaf26..2039d71 100644
>> >> --- a/drivers/gpu/drm/i915/i915_reg.h
>> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> >> @@ -1968,6 +1968,43 @@
>> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>> >>
>> >> +/* VLV eDP PSR registers */
>> >> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
>> >> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
>> >> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
>> >> +#define  VLV_EDP_PSR_RESET                   (1<<1)
>> >> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
>> >> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
>> >> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
>> >> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
>> >> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
>> >> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
>> >> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
>> >> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
>> >> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
>> >> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
>> >> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
>> >
>> > Can we just name the PSR registers like in the spec? Eg. just
>> > VLV_PSRCTL(). Would make it easier to compare things w/ the spec.
>> >
>>
>> Done.
>>
>> >> +
>> >> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
>> >> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
>> >> +#define VLV_EDP_VSC_SDP_REG(pipe)    _PIPE(pipe, _VSCSDPA, _VSCSDPB)
>> >> +
>> >> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
>> >> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
>> >> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
>> >> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
>> >> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
>> >> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
>> >> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
>> >> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
>> >> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
>> >> +#define  VLV_EDP_PSR_EXIT            (5<<0)
>> >> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
>> >> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
>> >> +
>> >>  /* HSW+ eDP PSR registers */
>> >>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>> >>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
>> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> >> index 1a9aa19..081c8e2 100644
>> >> --- a/drivers/gpu/drm/i915/intel_display.c
>> >> +++ b/drivers/gpu/drm/i915/intel_display.c
>> >> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>> >>       u32 base = 0, pos = 0;
>> >>       bool visible;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       if (on)
>> >>               base = intel_crtc->cursor_addr;
>> >>
>> >> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
>> >>
>> >>       if (dev_priv->info->gen >= 6)
>> >>               gen6_rps_idle(dev->dev_private);
>> >> +
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_update(dev);
>> >>  }
>> >>
>> >> +
>> >>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>> >>                       struct intel_ring_buffer *ring)
>> >>  {
>> >>       struct drm_device *dev = obj->base.dev;
>> >>       struct drm_crtc *crtc;
>> >>
>> >> -     if (!i915.powersave)
>> >> -             return;
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >>
>> >>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> >>               if (!crtc->fb)
>> >> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>> > nav>    if (work == NULL)
>>
>> sorry, I didn't get this..
>> what did you mean?
>
> Nothing. Just managed to misplace a few characters here I guess. I blame
> vim :)
>
>>
>> >>               return -ENOMEM;
>> >>
>> >> +     /* Inactivate PSR early in page flip */
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       work->event = event;
>> >>       work->crtc = crtc;
>> >>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
>> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> >> index 30d4350..e9a0ace 100644
>> >> --- a/drivers/gpu/drm/i915/intel_dp.c
>> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> >> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>> >>       }
>> >>  }
>> >>
>> >> -static bool is_edp_psr(struct drm_device *dev)
>> >> +static bool is_edp_psr(struct intel_dp *intel_dp)
>> >> +{
>> >> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>> >> +}
>> >> +
>> >> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>> >>  {
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     uint32_t val;
>> >>
>> >> -     return dev_priv->psr.sink_support;
>> >> +     val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
>> >> +             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>> >>  }
>> >>
>> >>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>> >>  {
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>
>> >> -     if (!HAS_PSR(dev))
>> >> -             return false;
>> >> +     if (HAS_PSR(dev)) {
>> >> +             if (IS_VALLEYVIEW(dev))
>> >> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
>> >> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
>> >> +             else
>> >> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     }
>> >>
>> >> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     return false;
>> >>  }
>> >>
>> >>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> >> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> >>
>> >>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>> >>  {
>> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>       struct edp_vsc_psr psr_vsc;
>> >> +     uint32_t val;
>> >>
>> >>       if (dev_priv->psr.setup_done)
>> >>               return;
>> >>
>> >> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> >> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
>> >> -     psr_vsc.sdp_header.HB0 = 0;
>> >> -     psr_vsc.sdp_header.HB1 = 0x7;
>> >> -     psr_vsc.sdp_header.HB2 = 0x2;
>> >> -     psr_vsc.sdp_header.HB3 = 0x8;
>> >> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
>> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
>> >> +
>> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
>> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
>> >> +     } else {
>> >> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> >> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
>> >> +             psr_vsc.sdp_header.HB0 = 0;
>> >> +             psr_vsc.sdp_header.HB1 = 0x7;
>> >> +             psr_vsc.sdp_header.HB2 = 0x2;
>> >> +             psr_vsc.sdp_header.HB3 = 0x8;
>> >> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>> >>
>> >> -     /* Avoid continuous PSR exit by masking memup and hpd */
>> >> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> >> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> >> +             /* Avoid continuous PSR exit by masking memup and hpd */
>> >> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> >> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> >> +     }
>> >>
>> >>       dev_priv->psr.setup_done = true;
>> >>  }
>> >>
>> >> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >> +{
>> >> +     /* Enable PSR in sink */
>> >> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
>> >> +                                 DP_PSR_ENABLE);
>> >
>> > Don't we want the same main-link poweroff logic as HSW?
>>
>>
>> I can't remember why I'm not disabling main link here... So I did a
>> quickly try now and failure on tests was huge... so let's keep it
>> simple for now ;)
>
> I think you are disabling the main link currently. Or at least you're
> telling the sink that main link is going to be turned off, and you also
> leave the VLV_EDP_PSR_SRC_TRANSMITTER_STATE bit unset, so I think that
> should make the main link turn off. Well, since the pipe and port remain
> active, I don't know if the link actually turns off.
>
> I would assume that if you don't turn off the link, it would be easier
> to keep things happy. A bit weird that you had the opposite result.
>
> BTW now that I look at the HSW code, it seems buggy. When the sink
> doesn't require link training, we tell it that we're going to turn the
> link off, otherwise we tell it link will be on. But then we actually do
> the opposite in intel_edp_psr_enable_source().

afaI-can-remember I followed hsw-pm guide on this... but I might be wrong...
I'll comeback to psr hsw later anyway than I verify that and fix if needed.

>
>>
>> > Or maybe we
>> > should just keep the main link on always as long as we can't enter
>> > the low power states w/ DPLL/pipe/port off.
>> >
>> > Did you already figure out why that's not happening? Looking at the
>> > PSRSTAT registers, my guess is that D0i1 is where we end up currently,
>> > and that doesn't actually turn off anything but the planes (to stop
>> > memory fetches). D0i2 would turn off everything.
>>
>> no idea.. :(
>
> Did you check the status bit BTW? Does it say D0i1 or D0i2 when you're
> in PSR?

D0i1

>
>>
>> > But I guess we should anyway do this in steps. First getting the
>> > current stuff in, then trying to get into D0i2 state, and finally
>> > getting the display power well turned off when in PSR.
>>
>> Agree.
>>
>> >
>> > I think once we get to working on D0i2, we'll need to move the PSR
>> > wakeup to happen from a workqueue since it essentially requires a
>> > full modeset. Even now in your code it's somewhat questionable
>> > since you're doing stuff like aux transfers while holding
>> > struct_mutex.
>>
>> uhm... anything we should try now to improve?
>
> Hmm. We already seem to do some PSR setup while holding struct_mutex,
> but we don't hold it always. Although I think w/ HSW we end up
> protecting the PSR state w/ the modeset locks since we only fiddle
> with it during modesets. So for HSW we should just move the PSR update
> call in set_base outside struct_mutex.

I'm planning to change it on HSW to allow a kind of inactivate as well...

>
> But then for VLV, you want to call it from various places that already
> hold struct_mutex, so it's getting messy. Just moving it to a workqueue
> would seem like the easiest option here, and then you could grab the
> modeset locks in the work function.

uhm... I'm not sure... I don't think we need to delay the
psr_enable... the only issue I see here is double setup or psr-enable
along with psr-reset (inactivate)... don't you think a simple mutex
for psr_setup would solve in a simpler way?

>
>>
>> >
>> >> +}
>> >> +
>> >>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>> >>  }
>> >>
>> >> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
>> >> +{
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >> +
>> >> +     uint32_t idle_frames = 1;
>> >> +     uint32_t val;
>> >> +
>> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>> >
>> > I don't think we want to preserve anything here. We need to make sure
>> > everything is initialized correctly rather than trusting some old junk
>> > in the register.
>>
>> Done.
>>
>> >
>> >> +     val |= VLV_EDP_PSR_ENABLE;
>> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> >> +
>> >> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
>> >> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
>> >> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
>> >> +
>> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> >> +}
>> >> +
>> >>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>> >>               return false;
>> >>       }
>> >>
>> >> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> >> -         (dig_port->port != PORT_A)) {
>> >> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> >> +                          (dig_port->port != PORT_A))) {
>> >>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>> >>               return false;
>> >>       }
>> >> @@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>> >>               return false;
>> >>       }
>> >>
>> >> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
>> >> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
>> >> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
>> >> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
>> >> +             return false;
>> >> +     }
>> >> +
>> >>       dev_priv->psr.source_ok = true;
>> >>       return true;
>> >>  }
>> >>
>> >>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>> >>  {
>> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >>
>> >> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
>> >> -         intel_edp_is_psr_enabled(dev))
>> >> -             return;
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
>> >> +                     return;
>> >> +     } else
>> >> +             if (intel_edp_is_psr_enabled(dev))
>> >> +                     return;
>> >>
>> >>       /* Setup PSR once */
>> >>       intel_edp_psr_setup(intel_dp);
>> >>
>> >>       /* Enable PSR on the panel */
>> >> -     intel_edp_psr_enable_sink(intel_dp);
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_enable_sink(intel_dp);
>> >> +     else
>> >> +             intel_edp_psr_enable_sink(intel_dp);
>> >>
>> >>       /* Enable PSR on the host */
>> >> -     intel_edp_psr_enable_source(intel_dp);
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_enable_source(intel_dp);
>> >> +     else
>> >> +             intel_edp_psr_enable_source(intel_dp);
>> >> +
>> >> +     dev_priv->psr.active = true;
>> >>  }
>> >>
>> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
>> >>  {
>> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> +     if (!is_edp_psr(intel_dp))
>> >> +             return;
>> >>
>> >> -     if (intel_edp_psr_match_conditions(intel_dp) &&
>> >> -         !intel_edp_is_psr_enabled(dev))
>> >> +     if (intel_edp_psr_match_conditions(intel_dp))
>> >>               intel_edp_psr_do_enable(intel_dp);
>> >>  }
>> >>
>> >> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
>> >> +{
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >> +     uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
>> >> +
>> >> +     if (!dev_priv->psr.setup_done)
>> >> +             return;
>> >> +
>> >> +     intel_edp_psr_inactivate(dev);
>> >> +
>> >> +     if (val & VLV_EDP_PSR_IN_TRANS)
>> >> +             udelay(250);
>> >
>> > Might we want a warning if the bit doesn't go down in expected time?
>>
>> Done.
>>
>> >
>> >> +
>> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>> >> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
>> >> +     val &= ~VLV_EDP_PSR_ENABLE;
>> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> >> +}
>> >> +
>> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
>> >>  {
>> >>       struct intel_encoder *encoder;
>> >>       struct intel_dp *intel_dp = NULL;
>> >> +     struct intel_crtc *intel_crtc;
>> >>
>> >>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>> >>               if (encoder->type == INTEL_OUTPUT_EDP) {
>> >>                       intel_dp = enc_to_intel_dp(&encoder->base);
>> >>
>> >> -                     if (!is_edp_psr(dev))
>> >> +                     if (!is_edp_psr(intel_dp))
>> >>                               return;
>> >>
>> >> -                     if (!intel_edp_psr_match_conditions(intel_dp))
>> >> -                             intel_edp_psr_disable(intel_dp);
>> >> -                     else
>> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> >> +
>> >> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
>> >> +                             if (IS_VALLEYVIEW(dev))
>> >> +                                     vlv_edp_psr_disable(intel_dp);
>> >> +                             else
>> >> +                                     intel_edp_psr_disable(intel_dp);
>> >> +                     } else
>> >>                               if (!intel_edp_is_psr_enabled(dev))
>> >>                                       intel_edp_psr_do_enable(intel_dp);
>> >>               }
>> >>  }
>> >>
>> >> +void intel_edp_psr_inactivate(struct drm_device *dev)
>> >> +{
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_encoder *encoder;
>> >> +     struct intel_crtc *intel_crtc;
>> >> +     struct intel_dp *intel_dp = NULL;
>> >> +
>> >> +     if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
>> >> +             return;
>> >> +
>> >> +     list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>> >> +             if (encoder->type == INTEL_OUTPUT_EDP) {
>> >> +                     intel_dp = enc_to_intel_dp(&encoder->base);
>> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> >> +
>> >> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
>> >> +                                                         intel_crtc->pipe))
>> >> +                             continue;
>> >> +
>> >> +                     dev_priv->psr.active = false;
>> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
>> >> +                                VLV_EDP_PSR_RESET);
>> >> +                     /* WaClearPSRReset:vlv */
>> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
>> >> +
>> >> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>> >> +             }
>> >> +}
>> >> +
>> >>  static void intel_disable_dp(struct intel_encoder *encoder)
>> >>  {
>> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>> >>       enum port port = dp_to_dig_port(intel_dp)->port;
>> >>       struct drm_device *dev = encoder->base.dev;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_disable(intel_dp);
>> >> +
>> >>       /* Make sure the panel is off before trying to change the mode. But also
>> >>        * ensure that we have vdd while we switch off the panel. */
>> >>       intel_edp_backlight_off(intel_dp);
>> >> @@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>> >>
>> >>       intel_edp_backlight_on(intel_dp);
>> >> +     intel_edp_psr_enable(intel_dp);
>> >>  }
>> >>
>> >>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
>> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> >> index 71c1371..82026ef 100644
>> >> --- a/drivers/gpu/drm/i915/intel_drv.h
>> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> >> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_update(struct drm_device *dev);
>> >> +void intel_edp_psr_inactivate(struct drm_device *dev);
>> >>
>> >>
>> >>  /* intel_dsi.c */
>> >> --
>> >> 1.8.1.2
>> >
>> > --
>> > Ville Syrjälä
>> > Intel OTC
>>
>> Thank you very much!
>>
>> --
>> Rodrigo Vivi
>> Blog: http://blog.vivi.eng.br
>
> --
> Ville Syrjälä
> Intel OTC



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 17:48                     ` Rodrigo Vivi
@ 2014-01-29 18:24                       ` Ville Syrjälä
  0 siblings, 0 replies; 45+ messages in thread
From: Ville Syrjälä @ 2014-01-29 18:24 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 03:48:21PM -0200, Rodrigo Vivi wrote:
> On Wed, Jan 29, 2014 at 2:38 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Wed, Jan 29, 2014 at 01:47:00PM -0200, Rodrigo Vivi wrote:
> >> On Wed, Jan 29, 2014 at 12:56 PM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
> >> >> This patch adds PSR Support to Baytrail.
> >> >>
> >> >> Baytrail cannot easily detect screen updates and force PSR exit.
> >> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
> >> >> and update to enable it back on next display mark_idle.
> >> >>
> >> >> v2: Also inactivate PSR on cursor update.
> >> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >> >>     early on page flip besides avoid initializing inactive/active flag
> >> >>     more than once.
> >> >> v4: Fix identation issues.
> >> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >> >>     support disabled by for now since it isn't working properly yet.
> >> >> v6: Removing forgotten comment and useless clkgating definition.
> >> >>
> >> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> >> >> ---
> >> >>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
> >> >>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
> >> >>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
> >> >>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
> >> >>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
> >> >>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
> >> >>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
> >> >>  7 files changed, 267 insertions(+), 39 deletions(-)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >> >> index 4b852c6..c28de65 100644
> >> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> >> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >> >> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >> >>       struct drm_device *dev = node->minor->dev;
> >> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> >>       u32 psrperf = 0;
> >> >> +     u32 statA = 0;
> >> >> +     u32 statB = 0;
> >> >>       bool enabled = false;
> >> >>
> >> >>       intel_runtime_pm_get(dev_priv);
> >> >> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >> >>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
> >> >>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
> >> >>
> >> >> -     enabled = HAS_PSR(dev) &&
> >> >> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> >> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
> >> >> +     if (HAS_PSR(dev)) {
> >> >> +             if (IS_VALLEYVIEW(dev)) {
> >> >> +                     statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
> >> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> >> +                     statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
> >> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> >> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> >> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
> >> >> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> >> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
> >> >> +             } else
> >> >> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> >> +     }
> >> >> +     seq_printf(m, "Enabled: %s", yesno(enabled));
> >> >>
> >> >> -     if (HAS_PSR(dev))
> >> >> +     if (IS_VALLEYVIEW(dev)) {
> >> >> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> >> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> >> +                     seq_puts(m, " pipe A");
> >> >> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> >> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> >> +                     seq_puts(m, " pipe B");
> >> >> +     }
> >> >> +
> >> >> +     seq_puts(m, "\n");
> >> >> +
> >> >> +     /* VLV PSR has no kind of performance counter */
> >> >> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
> >> >>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
> >> >>                       EDP_PSR_PERF_CNT_MASK;
> >> >> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> >> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> >> +     }
> >> >>
> >> >>       intel_runtime_pm_put(dev_priv);
> >> >>       return 0;
> >> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> >> >> index 7c53d4d..34dee24 100644
> >> >> --- a/drivers/gpu/drm/i915/i915_drv.h
> >> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
> >> >> @@ -747,6 +747,7 @@ struct i915_psr {
> >> >>       bool sink_support;
> >> >>       bool source_ok;
> >> >>       bool setup_done;
> >> >> +     bool active;
> >> >>  };
> >> >>
> >> >>  enum intel_pch {
> >> >> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
> >> >>
> >> >>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
> >> >>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
> >> >> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
> >> >> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
> >> >> +                              IS_VALLEYVIEW(dev))
> >> >>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
> >> >>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
> >> >>
> >> >> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> >> >> index 39770f7..01137fe 100644
> >> >> --- a/drivers/gpu/drm/i915/i915_gem.c
> >> >> +++ b/drivers/gpu/drm/i915/i915_gem.c
> >> >> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
> >> >>               goto unlock;
> >> >>       }
> >> >>
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >> +
> >> >>       /* Try to flush the object off the GPU without holding the lock.
> >> >>        * We will repeat the flush holding the lock in the normal manner
> >> >>        * to catch cases where we are gazumped.
> >> >> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
> >> >>       if (ret)
> >> >>               return ret;
> >> >>
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >> +
> >> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >> >>       if (&obj->base == NULL) {
> >> >>               ret = -ENOENT;
> >> >> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
> >> >>       if (ret)
> >> >>               return ret;
> >> >>
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >
> >> > The locking for PSR seems to be as fubar as for FBC. Also the front
> >> > buffer tracking is missing, but I guess I need to make that work for FBC
> >> > first, and then we need to figure out how to tie it in w/ PSR.
> >> >
> >>
> >> agree... I'll wait your fbc work.
> >>
> >> >> +
> >> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >> >>       if (&obj->base == NULL) {
> >> >>               ret = -ENOENT;
> >> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> >> >> index cbbaf26..2039d71 100644
> >> >> --- a/drivers/gpu/drm/i915/i915_reg.h
> >> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
> >> >> @@ -1968,6 +1968,43 @@
> >> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
> >> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
> >> >>
> >> >> +/* VLV eDP PSR registers */
> >> >> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
> >> >> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
> >> >> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
> >> >> +#define  VLV_EDP_PSR_RESET                   (1<<1)
> >> >> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
> >> >> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
> >> >> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
> >> >> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
> >> >> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
> >> >> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
> >> >> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
> >> >> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
> >> >> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
> >> >> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
> >> >> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
> >> >
> >> > Can we just name the PSR registers like in the spec? Eg. just
> >> > VLV_PSRCTL(). Would make it easier to compare things w/ the spec.
> >> >
> >>
> >> Done.
> >>
> >> >> +
> >> >> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
> >> >> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
> >> >> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
> >> >> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
> >> >> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
> >> >> +#define VLV_EDP_VSC_SDP_REG(pipe)    _PIPE(pipe, _VSCSDPA, _VSCSDPB)
> >> >> +
> >> >> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
> >> >> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
> >> >> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
> >> >> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
> >> >> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
> >> >> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
> >> >> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
> >> >> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
> >> >> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
> >> >> +#define  VLV_EDP_PSR_EXIT            (5<<0)
> >> >> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
> >> >> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
> >> >> +
> >> >>  /* HSW+ eDP PSR registers */
> >> >>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
> >> >>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
> >> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> >> >> index 1a9aa19..081c8e2 100644
> >> >> --- a/drivers/gpu/drm/i915/intel_display.c
> >> >> +++ b/drivers/gpu/drm/i915/intel_display.c
> >> >> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >> >>       u32 base = 0, pos = 0;
> >> >>       bool visible;
> >> >>
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >> +
> >> >>       if (on)
> >> >>               base = intel_crtc->cursor_addr;
> >> >>
> >> >> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
> >> >>
> >> >>       if (dev_priv->info->gen >= 6)
> >> >>               gen6_rps_idle(dev->dev_private);
> >> >> +
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_update(dev);
> >> >>  }
> >> >>
> >> >> +
> >> >>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
> >> >>                       struct intel_ring_buffer *ring)
> >> >>  {
> >> >>       struct drm_device *dev = obj->base.dev;
> >> >>       struct drm_crtc *crtc;
> >> >>
> >> >> -     if (!i915.powersave)
> >> >> -             return;
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >>
> >> >>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> >> >>               if (!crtc->fb)
> >> >> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >> > nav>    if (work == NULL)
> >>
> >> sorry, I didn't get this..
> >> what did you mean?
> >
> > Nothing. Just managed to misplace a few characters here I guess. I blame
> > vim :)
> >
> >>
> >> >>               return -ENOMEM;
> >> >>
> >> >> +     /* Inactivate PSR early in page flip */
> >> >> +     if (IS_VALLEYVIEW(dev))
> >> >> +             intel_edp_psr_inactivate(dev);
> >> >> +
> >> >>       work->event = event;
> >> >>       work->crtc = crtc;
> >> >>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
> >> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> >> >> index 30d4350..e9a0ace 100644
> >> >> --- a/drivers/gpu/drm/i915/intel_dp.c
> >> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
> >> >> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> >> >>       }
> >> >>  }
> >> >>
> >> >> -static bool is_edp_psr(struct drm_device *dev)
> >> >> +static bool is_edp_psr(struct intel_dp *intel_dp)
> >> >> +{
> >> >> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
> >> >> +}
> >> >> +
> >> >> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
> >> >>  {
> >> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> >> +     uint32_t val;
> >> >>
> >> >> -     return dev_priv->psr.sink_support;
> >> >> +     val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
> >> >> +             VLV_EDP_PSR_CURR_STATE_MASK;
> >> >> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> >> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
> >> >>  }
> >> >>
> >> >>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
> >> >>  {
> >> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> >>
> >> >> -     if (!HAS_PSR(dev))
> >> >> -             return false;
> >> >> +     if (HAS_PSR(dev)) {
> >> >> +             if (IS_VALLEYVIEW(dev))
> >> >> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
> >> >> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
> >> >> +             else
> >> >> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> >> +     }
> >> >>
> >> >> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> >> +     return false;
> >> >>  }
> >> >>
> >> >>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >> >> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >> >>
> >> >>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
> >> >>  {
> >> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> >>       struct edp_vsc_psr psr_vsc;
> >> >> +     uint32_t val;
> >> >>
> >> >>       if (dev_priv->psr.setup_done)
> >> >>               return;
> >> >>
> >> >> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> >> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> >> -     psr_vsc.sdp_header.HB0 = 0;
> >> >> -     psr_vsc.sdp_header.HB1 = 0x7;
> >> >> -     psr_vsc.sdp_header.HB2 = 0x2;
> >> >> -     psr_vsc.sdp_header.HB3 = 0x8;
> >> >> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >> >> +     if (IS_VALLEYVIEW(dev)) {
> >> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
> >> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
> >> >> +
> >> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
> >> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
> >> >> +     } else {
> >> >> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> >> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> >> +             psr_vsc.sdp_header.HB0 = 0;
> >> >> +             psr_vsc.sdp_header.HB1 = 0x7;
> >> >> +             psr_vsc.sdp_header.HB2 = 0x2;
> >> >> +             psr_vsc.sdp_header.HB3 = 0x8;
> >> >> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >> >>
> >> >> -     /* Avoid continuous PSR exit by masking memup and hpd */
> >> >> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> >> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> >> +             /* Avoid continuous PSR exit by masking memup and hpd */
> >> >> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> >> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> >> +     }
> >> >>
> >> >>       dev_priv->psr.setup_done = true;
> >> >>  }
> >> >>
> >> >> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >> >> +{
> >> >> +     /* Enable PSR in sink */
> >> >> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> >> >> +                                 DP_PSR_ENABLE);
> >> >
> >> > Don't we want the same main-link poweroff logic as HSW?
> >>
> >>
> >> I can't remember why I'm not disabling main link here... So I did a
> >> quickly try now and failure on tests was huge... so let's keep it
> >> simple for now ;)
> >
> > I think you are disabling the main link currently. Or at least you're
> > telling the sink that main link is going to be turned off, and you also
> > leave the VLV_EDP_PSR_SRC_TRANSMITTER_STATE bit unset, so I think that
> > should make the main link turn off. Well, since the pipe and port remain
> > active, I don't know if the link actually turns off.
> >
> > I would assume that if you don't turn off the link, it would be easier
> > to keep things happy. A bit weird that you had the opposite result.
> >
> > BTW now that I look at the HSW code, it seems buggy. When the sink
> > doesn't require link training, we tell it that we're going to turn the
> > link off, otherwise we tell it link will be on. But then we actually do
> > the opposite in intel_edp_psr_enable_source().
> 
> afaI-can-remember I followed hsw-pm guide on this... but I might be wrong...
> I'll comeback to psr hsw later anyway than I verify that and fix if needed.
> 
> >
> >>
> >> > Or maybe we
> >> > should just keep the main link on always as long as we can't enter
> >> > the low power states w/ DPLL/pipe/port off.
> >> >
> >> > Did you already figure out why that's not happening? Looking at the
> >> > PSRSTAT registers, my guess is that D0i1 is where we end up currently,
> >> > and that doesn't actually turn off anything but the planes (to stop
> >> > memory fetches). D0i2 would turn off everything.
> >>
> >> no idea.. :(
> >
> > Did you check the status bit BTW? Does it say D0i1 or D0i2 when you're
> > in PSR?
> 
> D0i1

OK, as I suspected then.

> 
> >
> >>
> >> > But I guess we should anyway do this in steps. First getting the
> >> > current stuff in, then trying to get into D0i2 state, and finally
> >> > getting the display power well turned off when in PSR.
> >>
> >> Agree.
> >>
> >> >
> >> > I think once we get to working on D0i2, we'll need to move the PSR
> >> > wakeup to happen from a workqueue since it essentially requires a
> >> > full modeset. Even now in your code it's somewhat questionable
> >> > since you're doing stuff like aux transfers while holding
> >> > struct_mutex.
> >>
> >> uhm... anything we should try now to improve?
> >
> > Hmm. We already seem to do some PSR setup while holding struct_mutex,
> > but we don't hold it always. Although I think w/ HSW we end up
> > protecting the PSR state w/ the modeset locks since we only fiddle
> > with it during modesets. So for HSW we should just move the PSR update
> > call in set_base outside struct_mutex.
> 
> I'm planning to change it on HSW to allow a kind of inactivate as well...
> 
> >
> > But then for VLV, you want to call it from various places that already
> > hold struct_mutex, so it's getting messy. Just moving it to a workqueue
> > would seem like the easiest option here, and then you could grab the
> > modeset locks in the work function.
> 
> uhm... I'm not sure... I don't think we need to delay the
> psr_enable... the only issue I see here is double setup or psr-enable
> along with psr-reset (inactivate)... don't you think a simple mutex
> for psr_setup would solve in a simpler way?

intel_edp_psr_match_conditions() in its current definitely needs to be
protected by crtc.mutex to not race w/ page flips and modesets.
Currently you call it from the idle work, without any locks, so that's
already a problem. And we can't simply grab modeset locks there since
those are banned on the dev_priv->wq workqueue.

One idea might be to call intel_edp_psr_match_conditions() only from
places where we already have the crtc mutex. That's actually just the
modeset code, since we can't change tiling via page flips, so page flips
don't need to call it. Hmm. Oh we'd also need to call it from the sprite
code too. Anyways, then based on the result we'd set some per-crtc flag to
remind us whether PSR can be enabled for the pipe. Then when we're ready
to re-enable PSR we can just check the flag. That could be protected by
some psr mutex.

Also we need to at least disable PSR from some places where we already
hold struct_mutex, and holding that sucker needlessly is a bad idea.
So offloading the PSR disable to a workqueue seems like the sane
approach here since it already involves stuff like aux writes. So even
if we have the psr mutex and flag thingy it would still need to be done
from a workqueue.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:26                           ` Chris Wilson
@ 2014-01-29 19:20                             ` Daniel Vetter
  0 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2014-01-29 19:20 UTC (permalink / raw)
  To: Chris Wilson, Rodrigo Vivi, intel-gfx

On Wed, Jan 29, 2014 at 02:26:03PM +0000, Chris Wilson wrote:
> On Wed, Jan 29, 2014 at 12:23:15PM -0200, Rodrigo Vivi wrote:
> > ok, got it.
> > 
> > So, the correct here is to remove inactivate from set_domain and add
> > gem_bo_busy call on MMAP_GTT testcase?
> 
> That would match what we should do today. It's just whether we take the
> opportunity to define a consistent behaviour...

Afaik we don't do a gem_bo_busy after gtt access, at least no everwhere.
Which sucks, but meh. At least I've thought that the busy is just after
gpu rendering.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:55                 ` Rodrigo Vivi
@ 2014-01-29 19:21                   ` Daniel Vetter
  2014-02-01 11:34                     ` Chris Wilson
  0 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2014-01-29 19:21 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 12:55:35PM -0200, Rodrigo Vivi wrote:
> This patch adds PSR Support to Baytrail.
> 
> Baytrail cannot easily detect screen updates and force PSR exit.
> So we inactivate it on {busy_ioctl, sw_finish and mark_busy}
> and update to enable it back on next display mark_idle.
> 
> v2: Also inactivate PSR on cursor update.
> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>     early on page flip besides avoid initializing inactive/active flag
>     more than once.
> v4: Fix identation issues.
> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>     support disabled by for now since it isn't working properly yet.
> v6: Removing forgotten comment and useless clkgating definition.
> v7: Remove inactivate from set_domain. Chris warned this was semanticaly
>     wrong.

Like I've said I agree that it's not pretty, but I also think it's the
only thing we can do atm. For fbc we have the hardware-based fence
tracking, but it sounds like that's busted for psr on byt.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 15:50                 ` Rodrigo Vivi
@ 2014-01-30 13:02                   ` Chris Wilson
  2014-01-30 17:01                     ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Chris Wilson @ 2014-01-30 13:02 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 01:50:06PM -0200, Rodrigo Vivi wrote:
> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>  	u32 base = 0, pos = 0;
>  	bool visible;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		intel_edp_psr_inactivate(dev);
> +

Inactivate means that we turn off PSR for some period of time until idle
again, right? In the case of a moving cursor that means indefinitely.

Also it sounds overkill to have to disable PSR just for the cursor
sprite. Is there not some preferrable alternatives or hw that dtrt?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-30 13:02                   ` Chris Wilson
@ 2014-01-30 17:01                     ` Rodrigo Vivi
  2014-02-04 10:53                       ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-01-30 17:01 UTC (permalink / raw)
  To: Chris Wilson, Rodrigo Vivi, intel-gfx, Ville Syrjälä

On Thu, Jan 30, 2014 at 11:02 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> On Wed, Jan 29, 2014 at 01:50:06PM -0200, Rodrigo Vivi wrote:
>> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>>       u32 base = 0, pos = 0;
>>       bool visible;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             intel_edp_psr_inactivate(dev);
>> +
>
> Inactivate means that we turn off PSR for some period of time until idle
> again, right?

Yes, right.

> In the case of a moving cursor that means indefinitely.
That's true... So I think we really need a work queue delaying the enable.
Or do you have any better idea?

>
> Also it sounds overkill to have to disable PSR just for the cursor
> sprite. Is there not some preferrable alternatives or hw that dtrt?

Yeap, I totally agree. The other option implemented by other drivers
is to use PSR SW control mode where driver controls all entry and exit
flow, since Baytrail cannot do it right on HW mode. But even the force
exit on this case was using the PSR_RESET that I'm using on inactivate
function. and they exported that over ioctl.
So I preferred to let all this on kernel side using hardware as much
as possible and workarounding the cases where hardware buggy on screen
update detection, although it looks like an overkill for a single
cursor update. :/

> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 19:21                   ` Daniel Vetter
@ 2014-02-01 11:34                     ` Chris Wilson
  2014-02-04 10:49                       ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Chris Wilson @ 2014-02-01 11:34 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 08:21:41PM +0100, Daniel Vetter wrote:
> On Wed, Jan 29, 2014 at 12:55:35PM -0200, Rodrigo Vivi wrote:
> > This patch adds PSR Support to Baytrail.
> > 
> > Baytrail cannot easily detect screen updates and force PSR exit.
> > So we inactivate it on {busy_ioctl, sw_finish and mark_busy}
> > and update to enable it back on next display mark_idle.
> > 
> > v2: Also inactivate PSR on cursor update.
> > v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >     early on page flip besides avoid initializing inactive/active flag
> >     more than once.
> > v4: Fix identation issues.
> > v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >     support disabled by for now since it isn't working properly yet.
> > v6: Removing forgotten comment and useless clkgating definition.
> > v7: Remove inactivate from set_domain. Chris warned this was semanticaly
> >     wrong.
> 
> Like I've said I agree that it's not pretty, but I also think it's the
> only thing we can do atm. For fbc we have the hardware-based fence
> tracking, but it sounds like that's busted for psr on byt.

No, it also does not match current userspace.

X will :
1. take a GTT mapping of the frontbufer
2. call set-to-domain write=GTT
3. write into mmap
4. go to sleep for a second or more
5. goto 3.

Once it has a write=GTT mmapping and it has not been used for anything
else, it will not inform the kernel that it needs to change domain
again, because as far as it is aware the memory is still in the correct
domain and perfectly coherent.

Besides which I keep asking for a PSR property so X can switch to an
alternative rendering strategy that should be more power efficient and
PSR friendly.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-02-01 11:34                     ` Chris Wilson
@ 2014-02-04 10:49                       ` Daniel Vetter
  0 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2014-02-04 10:49 UTC (permalink / raw)
  To: Chris Wilson, Daniel Vetter, Rodrigo Vivi, intel-gfx

On Sat, Feb 01, 2014 at 11:34:02AM +0000, Chris Wilson wrote:
> On Wed, Jan 29, 2014 at 08:21:41PM +0100, Daniel Vetter wrote:
> > On Wed, Jan 29, 2014 at 12:55:35PM -0200, Rodrigo Vivi wrote:
> > > This patch adds PSR Support to Baytrail.
> > > 
> > > Baytrail cannot easily detect screen updates and force PSR exit.
> > > So we inactivate it on {busy_ioctl, sw_finish and mark_busy}
> > > and update to enable it back on next display mark_idle.
> > > 
> > > v2: Also inactivate PSR on cursor update.
> > > v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> > >     early on page flip besides avoid initializing inactive/active flag
> > >     more than once.
> > > v4: Fix identation issues.
> > > v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> > >     support disabled by for now since it isn't working properly yet.
> > > v6: Removing forgotten comment and useless clkgating definition.
> > > v7: Remove inactivate from set_domain. Chris warned this was semanticaly
> > >     wrong.
> > 
> > Like I've said I agree that it's not pretty, but I also think it's the
> > only thing we can do atm. For fbc we have the hardware-based fence
> > tracking, but it sounds like that's busted for psr on byt.
> 
> No, it also does not match current userspace.
> 
> X will :
> 1. take a GTT mapping of the frontbufer
> 2. call set-to-domain write=GTT
> 3. write into mmap
> 4. go to sleep for a second or more
> 5. goto 3.
> 
> Once it has a write=GTT mmapping and it has not been used for anything
> else, it will not inform the kernel that it needs to change domain
> again, because as far as it is aware the memory is still in the correct
> domain and perfectly coherent.

Oops, sounds like we need to have another testcase which does this, both
for fbc and psr. It sounds like we'd need to nuke psr completely for this
case in set_domain (when gtt writes are enforced) and only re-enable it on
the next pageflip. If that's too shitty for some platforms we care about
we could have a timer in place to shoot down gtt mmappings and restore psr
after one second or something like this. Ofc that means we also need to
frob the page fault paths a bit then.

This is getting less pretty by the minute :(

While we discuss rendering models: Can you please double-check the fbc/psr
testcase and look for any insane sequence/cornercase (like the above one)
that we've missed thus far?

> Besides which I keep asking for a PSR property so X can switch to an
> alternative rendering strategy that should be more power efficient and
> PSR friendly.

Agreed on that, but imo we need to first get the legacy crap going without
regressions. Once we have that in solid shape we can extend things with
all kinds of fancy madness (I'm also thinking of explicit damage flushing
and things like this). But we've never had a solid baseline for fbc/psr
ever ...
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-30 17:01                     ` Rodrigo Vivi
@ 2014-02-04 10:53                       ` Daniel Vetter
  2014-02-04 13:03                         ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2014-02-04 10:53 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Thu, Jan 30, 2014 at 03:01:08PM -0200, Rodrigo Vivi wrote:
> On Thu, Jan 30, 2014 at 11:02 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > On Wed, Jan 29, 2014 at 01:50:06PM -0200, Rodrigo Vivi wrote:
> >> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >>       u32 base = 0, pos = 0;
> >>       bool visible;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             intel_edp_psr_inactivate(dev);
> >> +
> >
> > Inactivate means that we turn off PSR for some period of time until idle
> > again, right?
> 
> Yes, right.
> 
> > In the case of a moving cursor that means indefinitely.
> That's true... So I think we really need a work queue delaying the enable.
> Or do you have any better idea?

Yeah, sounds like we need a delayed work-queue to re-enable psr, also for
gtt mmap writes. See Chris' latest crazy example of what the X server is
currently allowed to do.

> > Also it sounds overkill to have to disable PSR just for the cursor
> > sprite. Is there not some preferrable alternatives or hw that dtrt?
> 
> Yeap, I totally agree. The other option implemented by other drivers
> is to use PSR SW control mode where driver controls all entry and exit
> flow, since Baytrail cannot do it right on HW mode. But even the force
> exit on this case was using the PSR_RESET that I'm using on inactivate
> function. and they exported that over ioctl.
> So I preferred to let all this on kernel side using hardware as much
> as possible and workarounding the cases where hardware buggy on screen
> update detection, although it looks like an overkill for a single
> cursor update. :/

Yeah, exporting psr to userspace is imo a complete no-go. We can give
userspace hints and eventually go to an explicit damage tracking model,
but it's ultimately the kernel's responsibility to shovel pixels to the
screen.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-02-04 10:53                       ` Daniel Vetter
@ 2014-02-04 13:03                         ` Rodrigo Vivi
  2014-02-04 13:54                           ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-02-04 13:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

>> > In the case of a moving cursor that means indefinitely.
>> That's true... So I think we really need a work queue delaying the enable.
>> Or do you have any better idea?
>
> Yeah, sounds like we need a delayed work-queue to re-enable psr, also for
> gtt mmap writes. See Chris' latest crazy example of what the X server is
> currently allowed to do.

http://cgit.freedesktop.org/~vivijim/drm-intel/commit/?h=psr-baytrail-wq&id=f356c599db47dca4966dfb173282b111ce3055f5

But I'm not sure if I should do all with delayed schedule or still
calling this psr_update on mark_idle and just schedule work on cursor.
what do you think?


Please notice that besides the wq it also has mutex psr added on this:

http://cgit.freedesktop.org/~vivijim/drm-intel/commit/?h=psr-baytrail-wq&id=b18fb62af0d591cec593a75f7cf896b46e0cc91e

> Oops, sounds like we need to have another testcase which does this, both
> for fbc and psr. It sounds like we'd need to nuke psr completely for this
> case in set_domain (when gtt writes are enforced) and only re-enable it on
> the next pageflip. If that's too shitty for some platforms we care about
> we could have a timer in place to shoot down gtt mmappings and restore psr
> after one second or something like this. Ofc that means we also need to
> frob the page fault paths a bit then.

To be honest this passed on my mind and I did a local test with sleep
after set_domain, but test worked so I didn't mind with that... but
seems that it was only a conincidence or I put the sleep on a wrong
place...
Anyway I will include more test cases...
Anyway, do you think that above delayed work with 5 seconds would sove
this case? or do you still want I do something to avoid it getting
back between set_doamin and next page_flip?
But in this case isn't there a risk to get it disabled forever? like
in the old cursor without the delayed work?

> > Besides which I keep asking for a PSR property so X can switch to an
> > alternative rendering strategy that should be more power efficient and
> > PSR friendly.

> Agreed on that, but imo we need to first get the legacy crap going without
> regressions. Once we have that in solid shape we can extend things with
> all kinds of fancy madness (I'm also thinking of explicit damage flushing
> and things like this). But we've never had a solid baseline for fbc/psr
> ever ...

I agree with Daniel, mainly for the big pressure on getting PSR
Baytrail in asap.
I'm considering yet that full PSR rework to get it tied to pipe
config... But will do this later.
First I'd like to have one working with minimal userspace interaction needed.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-02-04 13:03                         ` Rodrigo Vivi
@ 2014-02-04 13:54                           ` Daniel Vetter
  2014-02-05 19:04                             ` [PATCH 2/2] " Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2014-02-04 13:54 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Tue, Feb 04, 2014 at 11:03:25AM -0200, Rodrigo Vivi wrote:
> >> > In the case of a moving cursor that means indefinitely.
> >> That's true... So I think we really need a work queue delaying the enable.
> >> Or do you have any better idea?
> >
> > Yeah, sounds like we need a delayed work-queue to re-enable psr, also for
> > gtt mmap writes. See Chris' latest crazy example of what the X server is
> > currently allowed to do.
> 
> http://cgit.freedesktop.org/~vivijim/drm-intel/commit/?h=psr-baytrail-wq&id=f356c599db47dca4966dfb173282b111ce3055f5
> 
> But I'm not sure if I should do all with delayed schedule or still
> calling this psr_update on mark_idle and just schedule work on cursor.
> what do you think?

You also need to tear down gtt mmaps to make sure we catch them, at least
for the gtt mmap write case. And add a bit of code to gem_fault to
invalidate psr if needed.

> Please notice that besides the wq it also has mutex psr added on this:
> 
> http://cgit.freedesktop.org/~vivijim/drm-intel/commit/?h=psr-baytrail-wq&id=b18fb62af0d591cec593a75f7cf896b46e0cc91e

tbh I haven't thought much yet about locking, but iirc the current stuff
is hapzardous. Ville looked into fixing this, but it seems to be fairly
complicated. Not sure whether we should aim for a common locking between
fbc/psr or not (since they both are closely related wrt their interactions
between modeset code and gem stuff).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 1/2] drm/i915: Update PSR on resume.
  2014-01-23 18:16 ` [PATCH 3/4] drm/i915: Update PSR on resume Rodrigo Vivi
@ 2014-02-05 19:04   ` Rodrigo Vivi
  0 siblings, 0 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2014-02-05 19:04 UTC (permalink / raw)
  To: intel-gfx

Since now on update is also been called out of set_base let's use
a mutex to protec psr state changes.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_drv.h     |  1 +
 drivers/gpu/drm/i915/i915_suspend.c |  4 ++++
 drivers/gpu/drm/i915/intel_dp.c     | 17 ++++++++++++++---
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7c53d4d..21470be 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,6 +747,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	struct mutex lock;
 };
 
 enum intel_pch {
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 56785e8..ffcba21 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -288,6 +288,10 @@ static void i915_restore_display(struct drm_device *dev)
 		I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
 	}
 
+	/* Force a full PSR setup on resume */
+	dev_priv->psr.setup_done = false;
+	intel_edp_psr_update(dev);
+
 	/* only restore FBC info on the platform that supports FBC*/
 	intel_disable_fbc(dev);
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 30d4350..80054bb 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1633,6 +1633,8 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	if (dev_priv->psr.setup_done)
 		return;
 
+	mutex_init(&dev_priv->psr.lock);
+
 	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
 	memset(&psr_vsc, 0, sizeof(psr_vsc));
 	psr_vsc.sdp_header.HB0 = 0;
@@ -1777,9 +1779,6 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 	    intel_edp_is_psr_enabled(dev))
 		return;
 
-	/* Setup PSR once */
-	intel_edp_psr_setup(intel_dp);
-
 	/* Enable PSR on the panel */
 	intel_edp_psr_enable_sink(intel_dp);
 
@@ -1790,10 +1789,16 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	/* Setup PSR once */
+	intel_edp_psr_setup(intel_dp);
+
+	mutex_lock(&dev_priv->psr.lock);
 	if (intel_edp_psr_match_conditions(intel_dp) &&
 	    !intel_edp_is_psr_enabled(dev))
 		intel_edp_psr_do_enable(intel_dp);
+	mutex_unlock(&dev_priv->psr.lock);
 }
 
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
@@ -1815,9 +1820,13 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp)
 
 void intel_edp_psr_update(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
 
+	if (!dev_priv->psr.setup_done)
+		return;
+
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
@@ -1825,11 +1834,13 @@ void intel_edp_psr_update(struct drm_device *dev)
 			if (!is_edp_psr(dev))
 				return;
 
+			mutex_lock(&dev_priv->psr.lock);
 			if (!intel_edp_psr_match_conditions(intel_dp))
 				intel_edp_psr_disable(intel_dp);
 			else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
+			mutex_unlock(&dev_priv->psr.lock);
 		}
 }
 
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 2/2] drm/i915: Add Baytrail PSR Support.
  2014-02-04 13:54                           ` Daniel Vetter
@ 2014-02-05 19:04                             ` Rodrigo Vivi
  2014-02-07 17:24                               ` Ville Syrjälä
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-02-05 19:04 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy}
and update to enable it back on next display mark_idle.

v2: Also inactivate PSR on cursor update.
v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
    early on page flip besides avoid initializing inactive/active flag
    more than once.
v4: Fix identation issues.
v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
    support disabled by for now since it isn't working properly yet.
v6: Removing forgotten comment and useless clkgating definition.
v7: Remove inactivate from set_domain. Chris warned this was semanticaly
    wrong.
v8: Accept Ville's suggestions: Use register's names matching spec and
    warn if transition took longer than it should.
v9: New version with delayed work to get PSR back. Disabling it on
    set_domain but not rescheduing it back until next finish_page_flip.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++-
 drivers/gpu/drm/i915/i915_drv.h      |   5 +-
 drivers/gpu/drm/i915/i915_gem.c      |  12 ++
 drivers/gpu/drm/i915/i915_reg.h      |  37 +++++
 drivers/gpu/drm/i915/i915_suspend.c  |   2 +-
 drivers/gpu/drm/i915/intel_display.c |  18 ++-
 drivers/gpu/drm/i915/intel_dp.c      | 256 ++++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 8 files changed, 323 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index bc8707f..2949c48 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 statA = 0;
+	u32 statB = 0;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "Enabled: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			statA = I915_READ(VLV_PSRSTAT(PIPE_A)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			statB = I915_READ(VLV_PSRSTAT(PIPE_B)) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
+	seq_printf(m, "Enabled: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (IS_VALLEYVIEW(dev)) {
+		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe A");
+		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+			seq_puts(m, " pipe B");
+	}
+
+	seq_puts(m, "\n");
+
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 21470be..87c346a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -747,7 +747,9 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool active;
 	struct mutex lock;
+	struct delayed_work work;
 };
 
 enum intel_pch {
@@ -1867,7 +1869,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39770f7..5ef1380 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1256,6 +1256,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		goto unlock;
 	}
 
+	/* Here we don't reschedule work to get PSR back because userspace
+	* can set domain and take as much as time it wants to write it.
+	* We only reschedule it back on next finish_page_flip. There is the
+	* risk of PSR be inactive forever depending on how compositor works,
+	* but this is the safest way to avoid loosing screen updates.
+	*/
+	intel_edp_psr_inactivate(dev, false);
+
 	/* Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -1299,6 +1307,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	intel_edp_psr_inactivate(dev, true);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
@@ -4059,6 +4069,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	intel_edp_psr_inactivate(dev, true);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cbbaf26..a5815d0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1968,6 +1968,43 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_VSCSDP(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index ffcba21..6b31020 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -289,8 +289,8 @@ static void i915_restore_display(struct drm_device *dev)
 	}
 
 	/* Force a full PSR setup on resume */
+	intel_edp_psr_inactivate(dev, false);
 	dev_priv->psr.setup_done = false;
-	intel_edp_psr_update(dev);
 
 	/* only restore FBC info on the platform that supports FBC*/
 	intel_disable_fbc(dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a9aa19..92d6df4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4451,9 +4451,13 @@ static void intel_connector_check_state(struct intel_connector *connector)
  * consider. */
 void intel_connector_dpms(struct drm_connector *connector, int mode)
 {
+	struct drm_device *dev = connector->dev;
+
 	/* All the simple cases only support two dpms states. */
-	if (mode != DRM_MODE_DPMS_ON)
+	if (mode != DRM_MODE_DPMS_ON) {
 		mode = DRM_MODE_DPMS_OFF;
+		intel_edp_psr_inactivate(dev, false);
+	}
 
 	if (mode == connector->dpms)
 		return;
@@ -7501,6 +7505,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	u32 base = 0, pos = 0;
 	bool visible;
 
+	intel_edp_psr_inactivate(dev, true);
+
 	if (on)
 		base = intel_crtc->cursor_addr;
 
@@ -8230,12 +8236,15 @@ void intel_mark_idle(struct drm_device *dev)
 		gen6_rps_idle(dev->dev_private);
 }
 
+
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 			struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_crtc *crtc;
 
+	intel_edp_psr_inactivate(dev, true);
+
 	if (!i915.powersave)
 		return;
 
@@ -8336,6 +8345,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 	queue_work(dev_priv->wq, &work->work);
 
 	trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
+
+	/* Get PSR back after set_domain inactivated it without rescheduling
+	* it back. */
+	schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(5000));
 }
 
 void intel_finish_page_flip(struct drm_device *dev, int pipe)
@@ -8688,6 +8701,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	/* Inactivate PSR early in page flip */
+	intel_edp_psr_inactivate(dev, true);
+
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 80054bb..576c204 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
-static bool is_edp_psr(struct drm_device *dev)
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	return dev_priv->psr.sink_support;
+	val = I915_READ(VLV_PSRSTAT(pipe)) &
+		VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev))
+			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
+				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
+		else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1624,32 +1638,60 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
 	POSTING_READ(ctl_reg);
 }
 
+static void intel_edp_psr_work(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(work, typeof(*dev_priv), psr.work.work);
+	struct drm_device *dev = dev_priv->dev;
+
+	intel_edp_psr_update(dev);
+}
+
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	mutex_init(&dev_priv->psr.lock);
-
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
-
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_VSCSDP(PIPE_A));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_VSCSDP(PIPE_A), val);
+
+		val  = I915_READ(VLV_VSCSDP(PIPE_B));
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_VSCSDP(PIPE_B), val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+					    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1680,6 +1722,27 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+
+	uint32_t idle_frames = 1;
+	uint32_t val = 0;
+
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1721,8 +1784,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1767,23 +1830,45 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
+	/* Baytrail supports per-pipe PSR configuration, however PSR on
+	* PIPE_B isn't working properly. So let's keep it disabled for now. */
+	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
+		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
+		return false;
+	}
+
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
-		return;
+	if (IS_VALLEYVIEW(dev)) {
+		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
+			return;
+	} else
+		if (intel_edp_is_psr_enabled(dev))
+			return;
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.active = true;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
@@ -1791,16 +1876,43 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	if (!is_edp_psr(intel_dp))
+		return;
+
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	mutex_lock(&dev_priv->psr.lock);
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
+	if (intel_edp_psr_match_conditions(intel_dp))
 		intel_edp_psr_do_enable(intel_dp);
 	mutex_unlock(&dev_priv->psr.lock);
 }
 
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val;
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev, false);
+
+	if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
+		      VLV_EDP_PSR_IN_TRANS) == 0, 250))
+		WARN(1, "PSR transition took longer than expected\n");
+
+	val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+}
+
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1823,6 +1935,7 @@ void intel_edp_psr_update(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
 	struct intel_dp *intel_dp = NULL;
+	struct intel_crtc *intel_crtc;
 
 	if (!dev_priv->psr.setup_done)
 		return;
@@ -1830,26 +1943,93 @@ void intel_edp_psr_update(struct drm_device *dev)
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
 		if (encoder->type == INTEL_OUTPUT_EDP) {
 			intel_dp = enc_to_intel_dp(&encoder->base);
-
-			if (!is_edp_psr(dev))
-				return;
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
 
 			mutex_lock(&dev_priv->psr.lock);
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 			mutex_unlock(&dev_priv->psr.lock);
 		}
 }
 
+void intel_edp_psr_do_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_connector *connector;
+	struct intel_encoder *encoder;
+	struct intel_crtc *intel_crtc;
+	struct intel_dp *intel_dp = NULL;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list,
+			    base.head) {
+
+		if (connector->base.dpms != DRM_MODE_DPMS_ON)
+			continue;
+
+		encoder = to_intel_encoder(connector->base.encoder);
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
+							    intel_crtc->pipe))
+				continue;
+
+			dev_priv->psr.active = false;
+
+			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe),
+				   VLV_EDP_PSR_RESET);
+			/* WaClearPSRReset:vlv */
+			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+	}
+}
+
+void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!IS_VALLEYVIEW(dev))
+		return;
+
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	/* If it was requested to not turn psr back delayed work must be
+	 * canceled even if it is already on inactivated state. */
+	if (!schedule_back)
+		cancel_delayed_work_sync(&dev_priv->psr.work);
+
+	if (!dev_priv->psr.active)
+		return;
+
+	cancel_delayed_work_sync(&dev_priv->psr.work);
+
+	intel_edp_psr_do_inactivate(dev);
+
+	if (schedule_back)
+		schedule_delayed_work(&dev_priv->psr.work,
+				      msecs_to_jiffies(5000));
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_backlight_off(intel_dp);
@@ -1906,6 +2086,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -3846,8 +4027,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 		BUG();
 	}
 
-	if (is_edp(intel_dp))
+	if (is_edp(intel_dp)) {
 		intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+		INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
+		mutex_init(&dev_priv->psr.lock);
+	}
 
 	error = intel_dp_i2c_init(intel_dp, intel_connector, name);
 	WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 71c1371..d8103f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back);
 
 
 /* intel_dsi.c */
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] drm/i915: Add Baytrail PSR Support.
  2014-02-05 19:04                             ` [PATCH 2/2] " Rodrigo Vivi
@ 2014-02-07 17:24                               ` Ville Syrjälä
  2014-02-07 18:05                                 ` Rodrigo Vivi
  0 siblings, 1 reply; 45+ messages in thread
From: Ville Syrjälä @ 2014-02-07 17:24 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Wed, Feb 05, 2014 at 05:04:31PM -0200, Rodrigo Vivi wrote:
> This patch adds PSR Support to Baytrail.
> 
> Baytrail cannot easily detect screen updates and force PSR exit.
> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy}
> and update to enable it back on next display mark_idle.
> 
> v2: Also inactivate PSR on cursor update.
> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>     early on page flip besides avoid initializing inactive/active flag
>     more than once.
> v4: Fix identation issues.
> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>     support disabled by for now since it isn't working properly yet.
> v6: Removing forgotten comment and useless clkgating definition.
> v7: Remove inactivate from set_domain. Chris warned this was semanticaly
>     wrong.
> v8: Accept Ville's suggestions: Use register's names matching spec and
>     warn if transition took longer than it should.
> v9: New version with delayed work to get PSR back. Disabling it on
>     set_domain but not rescheduing it back until next finish_page_flip.
> 
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++-
>  drivers/gpu/drm/i915/i915_drv.h      |   5 +-
>  drivers/gpu/drm/i915/i915_gem.c      |  12 ++
>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++
>  drivers/gpu/drm/i915/i915_suspend.c  |   2 +-
>  drivers/gpu/drm/i915/intel_display.c |  18 ++-
>  drivers/gpu/drm/i915/intel_dp.c      | 256 ++++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>  8 files changed, 323 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index bc8707f..2949c48 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>  	struct drm_device *dev = node->minor->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	u32 psrperf = 0;
> +	u32 statA = 0;
> +	u32 statB = 0;
>  	bool enabled = false;
>  
>  	intel_runtime_pm_get(dev_priv);
> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>  	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>  	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>  
> -	enabled = HAS_PSR(dev) &&
> -		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> -	seq_printf(m, "Enabled: %s\n", yesno(enabled));
> +	if (HAS_PSR(dev)) {
> +		if (IS_VALLEYVIEW(dev)) {
> +			statA = I915_READ(VLV_PSRSTAT(PIPE_A)) &
> +				VLV_EDP_PSR_CURR_STATE_MASK;
> +			statB = I915_READ(VLV_PSRSTAT(PIPE_B)) &
> +				VLV_EDP_PSR_CURR_STATE_MASK;
> +			enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +				   (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
> +				   (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +				   (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
> +		} else
> +			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	}
> +	seq_printf(m, "Enabled: %s", yesno(enabled));
>  
> -	if (HAS_PSR(dev))
> +	if (IS_VALLEYVIEW(dev)) {
> +		if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		    (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> +			seq_puts(m, " pipe A");
> +		if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		    (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> +			seq_puts(m, " pipe B");
> +	}
> +
> +	seq_puts(m, "\n");
> +
> +	/* VLV PSR has no kind of performance counter */
> +	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>  		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>  			EDP_PSR_PERF_CNT_MASK;
> -	seq_printf(m, "Performance_Counter: %u\n", psrperf);
> +		seq_printf(m, "Performance_Counter: %u\n", psrperf);
> +	}
>  
>  	intel_runtime_pm_put(dev_priv);
>  	return 0;
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 21470be..87c346a 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -747,7 +747,9 @@ struct i915_psr {
>  	bool sink_support;
>  	bool source_ok;
>  	bool setup_done;
> +	bool active;
>  	struct mutex lock;
> +	struct delayed_work work;
>  };
>  
>  enum intel_pch {
> @@ -1867,7 +1869,8 @@ struct drm_i915_file_private {
>  
>  #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
>  #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
> -#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
> +#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
> +				 IS_VALLEYVIEW(dev))
>  #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
>  #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 39770f7..5ef1380 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1256,6 +1256,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>  		goto unlock;
>  	}
>  
> +	/* Here we don't reschedule work to get PSR back because userspace
> +	* can set domain and take as much as time it wants to write it.
> +	* We only reschedule it back on next finish_page_flip. There is the
> +	* risk of PSR be inactive forever depending on how compositor works,
> +	* but this is the safest way to avoid loosing screen updates.
> +	*/
> +	intel_edp_psr_inactivate(dev, false);

This will still block until PSR is deactivated (aux communication and
all). That still seems like a bad idea to do while holding struct_mutex.

> +
>  	/* Try to flush the object off the GPU without holding the lock.
>  	 * We will repeat the flush holding the lock in the normal manner
>  	 * to catch cases where we are gazumped.
> @@ -1299,6 +1307,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>  	if (ret)
>  		return ret;
>  
> +	intel_edp_psr_inactivate(dev, true);
> +
>  	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>  	if (&obj->base == NULL) {
>  		ret = -ENOENT;
> @@ -4059,6 +4069,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>  	if (ret)
>  		return ret;
>  
> +	intel_edp_psr_inactivate(dev, true);
> +
>  	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>  	if (&obj->base == NULL) {
>  		ret = -ENOENT;
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index cbbaf26..a5815d0 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -1968,6 +1968,43 @@
>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>  
> +/* VLV eDP PSR registers */
> +#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
> +#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
> +#define  VLV_EDP_PSR_ENABLE			(1<<0)
> +#define  VLV_EDP_PSR_RESET			(1<<1)
> +#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
> +#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
> +#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
> +#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
> +#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
> +#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
> +#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
> +
> +#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
> +#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
> +#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
> +#define VLV_VSCSDP(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
> +
> +#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
> +#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
> +#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
> +#define  VLV_EDP_PSR_CURR_STATE_MASK	7
> +#define  VLV_EDP_PSR_DISABLED		(0<<0)
> +#define  VLV_EDP_PSR_INACTIVE		(1<<0)
> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
> +#define  VLV_EDP_PSR_EXIT		(5<<0)
> +#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
> +#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
> +
>  /* HSW+ eDP PSR registers */
>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>  #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
> diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
> index ffcba21..6b31020 100644
> --- a/drivers/gpu/drm/i915/i915_suspend.c
> +++ b/drivers/gpu/drm/i915/i915_suspend.c
> @@ -289,8 +289,8 @@ static void i915_restore_display(struct drm_device *dev)
>  	}
>  
>  	/* Force a full PSR setup on resume */
> +	intel_edp_psr_inactivate(dev, false);
>  	dev_priv->psr.setup_done = false;
> -	intel_edp_psr_update(dev);
>  
>  	/* only restore FBC info on the platform that supports FBC*/
>  	intel_disable_fbc(dev);
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 1a9aa19..92d6df4 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4451,9 +4451,13 @@ static void intel_connector_check_state(struct intel_connector *connector)
>   * consider. */
>  void intel_connector_dpms(struct drm_connector *connector, int mode)
>  {
> +	struct drm_device *dev = connector->dev;
> +
>  	/* All the simple cases only support two dpms states. */
> -	if (mode != DRM_MODE_DPMS_ON)
> +	if (mode != DRM_MODE_DPMS_ON) {
>  		mode = DRM_MODE_DPMS_OFF;
> +		intel_edp_psr_inactivate(dev, false);

Maybe check if this connector even has PSR enabled?

> +	}
>  
>  	if (mode == connector->dpms)
>  		return;
> @@ -7501,6 +7505,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>  	u32 base = 0, pos = 0;
>  	bool visible;
>  
> +	intel_edp_psr_inactivate(dev, true);

Don't need to inactivate unless the cursor is or was visible.

> +
>  	if (on)
>  		base = intel_crtc->cursor_addr;
>  
> @@ -8230,12 +8236,15 @@ void intel_mark_idle(struct drm_device *dev)
>  		gen6_rps_idle(dev->dev_private);
>  }
>  
> +
>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>  			struct intel_ring_buffer *ring)
>  {
>  	struct drm_device *dev = obj->base.dev;
>  	struct drm_crtc *crtc;
>  
> +	intel_edp_psr_inactivate(dev, true);
> +
>  	if (!i915.powersave)
>  		return;
>  
> @@ -8336,6 +8345,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>  	queue_work(dev_priv->wq, &work->work);
>  
>  	trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
> +
> +	/* Get PSR back after set_domain inactivated it without rescheduling
> +	* it back. */
> +	schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(5000));
>  }
>  
>  void intel_finish_page_flip(struct drm_device *dev, int pipe)
> @@ -8688,6 +8701,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	if (work == NULL)
>  		return -ENOMEM;
>  
> +	/* Inactivate PSR early in page flip */
> +	intel_edp_psr_inactivate(dev, true);
> +
>  	work->event = event;
>  	work->crtc = crtc;
>  	work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 80054bb..576c204 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static bool is_edp_psr(struct drm_device *dev)
> +static bool is_edp_psr(struct intel_dp *intel_dp)
> +{
> +	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
> +}
> +
> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> +	uint32_t val;
>  
> -	return dev_priv->psr.sink_support;
> +	val = I915_READ(VLV_PSRSTAT(pipe)) &
> +		VLV_EDP_PSR_CURR_STATE_MASK;
> +	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> +		(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>  }
>  
>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> -	if (!HAS_PSR(dev))
> -		return false;
> +	if (HAS_PSR(dev)) {
> +		if (IS_VALLEYVIEW(dev))
> +			return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
> +				vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
> +		else
> +			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	}
>  
> -	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> +	return false;
>  }
>  
>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> @@ -1624,32 +1638,60 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>  	POSTING_READ(ctl_reg);
>  }
>  
> +static void intel_edp_psr_work(struct work_struct *work)
> +{
> +	struct drm_i915_private *dev_priv =
> +		container_of(work, typeof(*dev_priv), psr.work.work);
> +	struct drm_device *dev = dev_priv->dev;
> +
> +	intel_edp_psr_update(dev);
> +}
> +
>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct edp_vsc_psr psr_vsc;
> +	uint32_t val;
>  
>  	if (dev_priv->psr.setup_done)
>  		return;
>  
> -	mutex_init(&dev_priv->psr.lock);
> -
> -	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> -	memset(&psr_vsc, 0, sizeof(psr_vsc));
> -	psr_vsc.sdp_header.HB0 = 0;
> -	psr_vsc.sdp_header.HB1 = 0x7;
> -	psr_vsc.sdp_header.HB2 = 0x2;
> -	psr_vsc.sdp_header.HB3 = 0x8;
> -	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> -
> -	/* Avoid continuous PSR exit by masking memup and hpd */
> -	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> -		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> +	if (IS_VALLEYVIEW(dev)) {
> +		val  = I915_READ(VLV_VSCSDP(PIPE_A));
> +		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> +		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> +		I915_WRITE(VLV_VSCSDP(PIPE_A), val);
> +
> +		val  = I915_READ(VLV_VSCSDP(PIPE_B));
> +		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> +		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> +		I915_WRITE(VLV_VSCSDP(PIPE_B), val);
> +	} else {
> +		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> +		memset(&psr_vsc, 0, sizeof(psr_vsc));
> +		psr_vsc.sdp_header.HB0 = 0;
> +		psr_vsc.sdp_header.HB1 = 0x7;
> +		psr_vsc.sdp_header.HB2 = 0x2;
> +		psr_vsc.sdp_header.HB3 = 0x8;
> +		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> +
> +		/* Avoid continuous PSR exit by masking memup and hpd */
> +		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> +			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> +	}
>  
>  	dev_priv->psr.setup_done = true;
>  }
>  
> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
> +{
> +	/* Enable PSR in sink */
> +	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> +					    DP_PSR_ENABLE);
> +}
> +
>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1680,6 +1722,27 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>  		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>  }
>  
> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
> +
> +	uint32_t idle_frames = 1;
> +	uint32_t val = 0;
> +
> +	val |= VLV_EDP_PSR_ENABLE;
> +	val &= ~VLV_EDP_PSR_MODE_MASK;
> +
> +	val |= VLV_EDP_PSR_MODE_HW_TIMER;
> +	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
> +	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
> +
> +	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
> +}
> +
>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1721,8 +1784,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> -	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> -	    (dig_port->port != PORT_A)) {
> +	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> +			     (dig_port->port != PORT_A))) {
>  		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>  		return false;
>  	}
> @@ -1767,23 +1830,45 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> +	/* Baytrail supports per-pipe PSR configuration, however PSR on
> +	* PIPE_B isn't working properly. So let's keep it disabled for now. */
> +	if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
> +		DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
> +		return false;
> +	}
> +
>  	dev_priv->psr.source_ok = true;
>  	return true;
>  }
>  
>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>  {
> -	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
>  
> -	if (!intel_edp_psr_match_conditions(intel_dp) ||
> -	    intel_edp_is_psr_enabled(dev))
> -		return;
> +	if (IS_VALLEYVIEW(dev)) {
> +		if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
> +			return;
> +	} else
> +		if (intel_edp_is_psr_enabled(dev))
> +			return;
>  
>  	/* Enable PSR on the panel */
> -	intel_edp_psr_enable_sink(intel_dp);
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_enable_sink(intel_dp);
> +	else
> +		intel_edp_psr_enable_sink(intel_dp);
>  
>  	/* Enable PSR on the host */
> -	intel_edp_psr_enable_source(intel_dp);
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_enable_source(intel_dp);
> +	else
> +		intel_edp_psr_enable_source(intel_dp);
> +
> +	dev_priv->psr.active = true;
>  }
>  
>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
> @@ -1791,16 +1876,43 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> +	if (!is_edp_psr(intel_dp))
> +		return;
> +
>  	/* Setup PSR once */
>  	intel_edp_psr_setup(intel_dp);
>  
>  	mutex_lock(&dev_priv->psr.lock);
> -	if (intel_edp_psr_match_conditions(intel_dp) &&
> -	    !intel_edp_is_psr_enabled(dev))
> +	if (intel_edp_psr_match_conditions(intel_dp))
>  		intel_edp_psr_do_enable(intel_dp);
>  	mutex_unlock(&dev_priv->psr.lock);
>  }
>  
> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_device *dev = intel_dig_port->base.base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc =
> +		to_intel_crtc(intel_dig_port->base.base.crtc);
> +	uint32_t val;
> +
> +	if (!dev_priv->psr.setup_done)
> +		return;
> +
> +	intel_edp_psr_inactivate(dev, false);
> +
> +	if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
> +		      VLV_EDP_PSR_IN_TRANS) == 0, 250))
> +		WARN(1, "PSR transition took longer than expected\n");
> +
> +	val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
> +	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
> +	val &= ~VLV_EDP_PSR_ENABLE;
> +	val &= ~VLV_EDP_PSR_MODE_MASK;
> +	I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
> +}
> +
>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>  {
>  	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -1823,6 +1935,7 @@ void intel_edp_psr_update(struct drm_device *dev)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_encoder *encoder;
>  	struct intel_dp *intel_dp = NULL;
> +	struct intel_crtc *intel_crtc;
>  
>  	if (!dev_priv->psr.setup_done)
>  		return;
> @@ -1830,26 +1943,93 @@ void intel_edp_psr_update(struct drm_device *dev)
>  	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>  		if (encoder->type == INTEL_OUTPUT_EDP) {
>  			intel_dp = enc_to_intel_dp(&encoder->base);
> -
> -			if (!is_edp_psr(dev))
> -				return;
> +			intel_crtc = to_intel_crtc(encoder->base.crtc);
>  
>  			mutex_lock(&dev_priv->psr.lock);
> -			if (!intel_edp_psr_match_conditions(intel_dp))
> -				intel_edp_psr_disable(intel_dp);
> -			else
> +			if (!intel_edp_psr_match_conditions(intel_dp)) {
> +				if (IS_VALLEYVIEW(dev))
> +					vlv_edp_psr_disable(intel_dp);
> +				else
> +					intel_edp_psr_disable(intel_dp);
> +			} else
>  				if (!intel_edp_is_psr_enabled(dev))
>  					intel_edp_psr_do_enable(intel_dp);
>  			mutex_unlock(&dev_priv->psr.lock);
>  		}
>  }
>  
> +void intel_edp_psr_do_inactivate(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_connector *connector;
> +	struct intel_encoder *encoder;
> +	struct intel_crtc *intel_crtc;
> +	struct intel_dp *intel_dp = NULL;
> +
> +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> +			    base.head) {
> +
> +		if (connector->base.dpms != DRM_MODE_DPMS_ON)
> +			continue;
> +
> +		encoder = to_intel_encoder(connector->base.encoder);
> +		if (encoder->type == INTEL_OUTPUT_EDP) {
> +
> +			intel_dp = enc_to_intel_dp(&encoder->base);
> +			intel_crtc = to_intel_crtc(encoder->base.crtc);

Still digging through the encoder and crtc pointers w/o holding any
modeset locks. Feels dangerous. intel_edp_psr_match_conditions() does
the same kind of stuff, and that too now gets called outside modeset
codepaths.

> +
> +			if (!vlv_edp_is_psr_enabled_on_pipe(dev,
> +							    intel_crtc->pipe))
> +				continue;
> +
> +			dev_priv->psr.active = false;
> +
> +			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe),
> +				   VLV_EDP_PSR_RESET);
> +			/* WaClearPSRReset:vlv */
> +			I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0);
> +
> +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +		}
> +	}
> +}
> +
> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	if (!IS_VALLEYVIEW(dev))
> +		return;
> +
> +	if (!dev_priv->psr.setup_done)
> +		return;
> +
> +	/* If it was requested to not turn psr back delayed work must be
> +	 * canceled even if it is already on inactivated state. */
> +	if (!schedule_back)
> +		cancel_delayed_work_sync(&dev_priv->psr.work);
> +
> +	if (!dev_priv->psr.active)
> +		return;

What if psr gets re-activated just after you checked above?

> +
> +	cancel_delayed_work_sync(&dev_priv->psr.work);
> +
> +	intel_edp_psr_do_inactivate(dev);
> +
> +	if (schedule_back)
> +		schedule_delayed_work(&dev_priv->psr.work,
> +				      msecs_to_jiffies(5000));
> +}
> +
>  static void intel_disable_dp(struct intel_encoder *encoder)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	enum port port = dp_to_dig_port(intel_dp)->port;
>  	struct drm_device *dev = encoder->base.dev;
>  
> +	if (IS_VALLEYVIEW(dev))
> +		vlv_edp_psr_disable(intel_dp);
> +
>  	/* Make sure the panel is off before trying to change the mode. But also
>  	 * ensure that we have vdd while we switch off the panel. */
>  	intel_edp_backlight_off(intel_dp);
> @@ -1906,6 +2086,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
>  	intel_edp_backlight_on(intel_dp);
> +	intel_edp_psr_enable(intel_dp);
>  }
>  
>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
> @@ -3846,8 +4027,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  		BUG();
>  	}
>  
> -	if (is_edp(intel_dp))
> +	if (is_edp(intel_dp)) {
>  		intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
> +		INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
> +		mutex_init(&dev_priv->psr.lock);

Initializing global state from a per-connector init function seems a bit
weird.

> +	}
>  
>  	error = intel_dp_i2c_init(intel_dp, intel_connector, name);
>  	WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 71c1371..d8103f9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>  void intel_edp_psr_update(struct drm_device *dev);
> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back);
>  
>  
>  /* intel_dsi.c */
> -- 
> 1.8.1.2

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] drm/i915: Add Baytrail PSR Support.
  2014-02-07 17:24                               ` Ville Syrjälä
@ 2014-02-07 18:05                                 ` Rodrigo Vivi
  2014-02-07 18:39                                   ` Ville Syrjälä
  0 siblings, 1 reply; 45+ messages in thread
From: Rodrigo Vivi @ 2014-02-07 18:05 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Fri, Feb 7, 2014 at 3:24 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Wed, Feb 05, 2014 at 05:04:31PM -0200, Rodrigo Vivi wrote:
>> This patch adds PSR Support to Baytrail.
>>
>> Baytrail cannot easily detect screen updates and force PSR exit.
>> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy}
>> and update to enable it back on next display mark_idle.
>>
>> v2: Also inactivate PSR on cursor update.
>> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>>     early on page flip besides avoid initializing inactive/active flag
>>     more than once.
>> v4: Fix identation issues.
>> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>>     support disabled by for now since it isn't working properly yet.
>> v6: Removing forgotten comment and useless clkgating definition.
>> v7: Remove inactivate from set_domain. Chris warned this was semanticaly
>>     wrong.
>> v8: Accept Ville's suggestions: Use register's names matching spec and
>>     warn if transition took longer than it should.
>> v9: New version with delayed work to get PSR back. Disabling it on
>>     set_domain but not rescheduing it back until next finish_page_flip.
>>
>> Cc: Chris Wilson <chris@chris-wilson.co.uk>
>> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
>> ---
>>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++-
>>  drivers/gpu/drm/i915/i915_drv.h      |   5 +-
>>  drivers/gpu/drm/i915/i915_gem.c      |  12 ++
>>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++
>>  drivers/gpu/drm/i915/i915_suspend.c  |   2 +-
>>  drivers/gpu/drm/i915/intel_display.c |  18 ++-
>>  drivers/gpu/drm/i915/intel_dp.c      | 256 ++++++++++++++++++++++++++++++-----
>>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>>  8 files changed, 323 insertions(+), 44 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> index bc8707f..2949c48 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>>       struct drm_device *dev = node->minor->dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       u32 psrperf = 0;
>> +     u32 statA = 0;
>> +     u32 statB = 0;
>>       bool enabled = false;
>>
>>       intel_runtime_pm_get(dev_priv);
>> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>>
>> -     enabled = HAS_PSR(dev) &&
>> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
>> +     if (HAS_PSR(dev)) {
>> +             if (IS_VALLEYVIEW(dev)) {
>> +                     statA = I915_READ(VLV_PSRSTAT(PIPE_A)) &
>> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> +                     statB = I915_READ(VLV_PSRSTAT(PIPE_B)) &
>> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
>> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
>> +             } else
>> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     }
>> +     seq_printf(m, "Enabled: %s", yesno(enabled));
>>
>> -     if (HAS_PSR(dev))
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> +                     seq_puts(m, " pipe A");
>> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> +                     seq_puts(m, " pipe B");
>> +     }
>> +
>> +     seq_puts(m, "\n");
>> +
>> +     /* VLV PSR has no kind of performance counter */
>> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>>                       EDP_PSR_PERF_CNT_MASK;
>> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> +     }
>>
>>       intel_runtime_pm_put(dev_priv);
>>       return 0;
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> index 21470be..87c346a 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -747,7 +747,9 @@ struct i915_psr {
>>       bool sink_support;
>>       bool source_ok;
>>       bool setup_done;
>> +     bool active;
>>       struct mutex lock;
>> +     struct delayed_work work;
>>  };
>>
>>  enum intel_pch {
>> @@ -1867,7 +1869,8 @@ struct drm_i915_file_private {
>>
>>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
>>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
>> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
>> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
>> +                              IS_VALLEYVIEW(dev))
>>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
>>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
>>
>> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>> index 39770f7..5ef1380 100644
>> --- a/drivers/gpu/drm/i915/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> @@ -1256,6 +1256,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>>               goto unlock;
>>       }
>>
>> +     /* Here we don't reschedule work to get PSR back because userspace
>> +     * can set domain and take as much as time it wants to write it.
>> +     * We only reschedule it back on next finish_page_flip. There is the
>> +     * risk of PSR be inactive forever depending on how compositor works,
>> +     * but this is the safest way to avoid loosing screen updates.
>> +     */
>> +     intel_edp_psr_inactivate(dev, false);
>
> This will still block until PSR is deactivated (aux communication and
> all). That still seems like a bad idea to do while holding struct_mutex.

So, what do you suggest here?

>
>> +
>>       /* Try to flush the object off the GPU without holding the lock.
>>        * We will repeat the flush holding the lock in the normal manner
>>        * to catch cases where we are gazumped.
>> @@ -1299,6 +1307,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>>       if (ret)
>>               return ret;
>>
>> +     intel_edp_psr_inactivate(dev, true);
>> +
>>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>>       if (&obj->base == NULL) {
>>               ret = -ENOENT;
>> @@ -4059,6 +4069,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>>       if (ret)
>>               return ret;
>>
>> +     intel_edp_psr_inactivate(dev, true);
>> +
>>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>>       if (&obj->base == NULL) {
>>               ret = -ENOENT;
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> index cbbaf26..a5815d0 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -1968,6 +1968,43 @@
>>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>>
>> +/* VLV eDP PSR registers */
>> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
>> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
>> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
>> +#define  VLV_EDP_PSR_RESET                   (1<<1)
>> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
>> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
>> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
>> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
>> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
>> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
>> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
>> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
>> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
>> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
>> +#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
>> +
>> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
>> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
>> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
>> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
>> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
>> +#define VLV_VSCSDP(pipe)     _PIPE(pipe, _VSCSDPA, _VSCSDPB)
>> +
>> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
>> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
>> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
>> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
>> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
>> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
>> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
>> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
>> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
>> +#define  VLV_EDP_PSR_EXIT            (5<<0)
>> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
>> +#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
>> +
>>  /* HSW+ eDP PSR registers */
>>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
>> diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
>> index ffcba21..6b31020 100644
>> --- a/drivers/gpu/drm/i915/i915_suspend.c
>> +++ b/drivers/gpu/drm/i915/i915_suspend.c
>> @@ -289,8 +289,8 @@ static void i915_restore_display(struct drm_device *dev)
>>       }
>>
>>       /* Force a full PSR setup on resume */
>> +     intel_edp_psr_inactivate(dev, false);
>>       dev_priv->psr.setup_done = false;
>> -     intel_edp_psr_update(dev);
>>
>>       /* only restore FBC info on the platform that supports FBC*/
>>       intel_disable_fbc(dev);
>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> index 1a9aa19..92d6df4 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -4451,9 +4451,13 @@ static void intel_connector_check_state(struct intel_connector *connector)
>>   * consider. */
>>  void intel_connector_dpms(struct drm_connector *connector, int mode)
>>  {
>> +     struct drm_device *dev = connector->dev;
>> +
>>       /* All the simple cases only support two dpms states. */
>> -     if (mode != DRM_MODE_DPMS_ON)
>> +     if (mode != DRM_MODE_DPMS_ON) {
>>               mode = DRM_MODE_DPMS_OFF;
>> +             intel_edp_psr_inactivate(dev, false);
>
> Maybe check if this connector even has PSR enabled?

the psr_inactivate already does that by checking psr.setup_done and psr.active.

>
>> +     }
>>
>>       if (mode == connector->dpms)
>>               return;
>> @@ -7501,6 +7505,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>>       u32 base = 0, pos = 0;
>>       bool visible;
>>
>> +     intel_edp_psr_inactivate(dev, true);
>
> Don't need to inactivate unless the cursor is or was visible.

so, below next retur after check visible and cursor_visible should be
enough, right?
>
>> +
>>       if (on)
>>               base = intel_crtc->cursor_addr;
>>
>> @@ -8230,12 +8236,15 @@ void intel_mark_idle(struct drm_device *dev)
>>               gen6_rps_idle(dev->dev_private);
>>  }
>>
>> +
>>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>>                       struct intel_ring_buffer *ring)
>>  {
>>       struct drm_device *dev = obj->base.dev;
>>       struct drm_crtc *crtc;
>>
>> +     intel_edp_psr_inactivate(dev, true);
>> +
>>       if (!i915.powersave)
>>               return;
>>
>> @@ -8336,6 +8345,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>>       queue_work(dev_priv->wq, &work->work);
>>
>>       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
>> +
>> +     /* Get PSR back after set_domain inactivated it without rescheduling
>> +     * it back. */
>> +     schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(5000));
>>  }
>>
>>  void intel_finish_page_flip(struct drm_device *dev, int pipe)
>> @@ -8688,6 +8701,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>>       if (work == NULL)
>>               return -ENOMEM;
>>
>> +     /* Inactivate PSR early in page flip */
>> +     intel_edp_psr_inactivate(dev, true);
>> +
>>       work->event = event;
>>       work->crtc = crtc;
>>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> index 80054bb..576c204 100644
>> --- a/drivers/gpu/drm/i915/intel_dp.c
>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>>       }
>>  }
>>
>> -static bool is_edp_psr(struct drm_device *dev)
>> +static bool is_edp_psr(struct intel_dp *intel_dp)
>> +{
>> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>> +}
>> +
>> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>>  {
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>> +     uint32_t val;
>>
>> -     return dev_priv->psr.sink_support;
>> +     val = I915_READ(VLV_PSRSTAT(pipe)) &
>> +             VLV_EDP_PSR_CURR_STATE_MASK;
>> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>>  }
>>
>>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>>  {
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>
>> -     if (!HAS_PSR(dev))
>> -             return false;
>> +     if (HAS_PSR(dev)) {
>> +             if (IS_VALLEYVIEW(dev))
>> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
>> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
>> +             else
>> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     }
>>
>> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> +     return false;
>>  }
>>
>>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> @@ -1624,32 +1638,60 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>>       POSTING_READ(ctl_reg);
>>  }
>>
>> +static void intel_edp_psr_work(struct work_struct *work)
>> +{
>> +     struct drm_i915_private *dev_priv =
>> +             container_of(work, typeof(*dev_priv), psr.work.work);
>> +     struct drm_device *dev = dev_priv->dev;
>> +
>> +     intel_edp_psr_update(dev);
>> +}
>> +
>>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>>  {
>> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct edp_vsc_psr psr_vsc;
>> +     uint32_t val;
>>
>>       if (dev_priv->psr.setup_done)
>>               return;
>>
>> -     mutex_init(&dev_priv->psr.lock);
>> -
>> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
>> -     psr_vsc.sdp_header.HB0 = 0;
>> -     psr_vsc.sdp_header.HB1 = 0x7;
>> -     psr_vsc.sdp_header.HB2 = 0x2;
>> -     psr_vsc.sdp_header.HB3 = 0x8;
>> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>> -
>> -     /* Avoid continuous PSR exit by masking memup and hpd */
>> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             val  = I915_READ(VLV_VSCSDP(PIPE_A));
>> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> +             I915_WRITE(VLV_VSCSDP(PIPE_A), val);
>> +
>> +             val  = I915_READ(VLV_VSCSDP(PIPE_B));
>> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> +             I915_WRITE(VLV_VSCSDP(PIPE_B), val);
>> +     } else {
>> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
>> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
>> +             psr_vsc.sdp_header.HB0 = 0;
>> +             psr_vsc.sdp_header.HB1 = 0x7;
>> +             psr_vsc.sdp_header.HB2 = 0x2;
>> +             psr_vsc.sdp_header.HB3 = 0x8;
>> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
>> +
>> +             /* Avoid continuous PSR exit by masking memup and hpd */
>> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> +     }
>>
>>       dev_priv->psr.setup_done = true;
>>  }
>>
>> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> +{
>> +     /* Enable PSR in sink */
>> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
>> +                                         DP_PSR_ENABLE);
>> +}
>> +
>>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1680,6 +1722,27 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>>  }
>>
>> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
>> +{
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> +
>> +     uint32_t idle_frames = 1;
>> +     uint32_t val = 0;
>> +
>> +     val |= VLV_EDP_PSR_ENABLE;
>> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> +
>> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
>> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
>> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
>> +
>> +     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
>> +}
>> +
>>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1721,8 +1784,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>>               return false;
>>       }
>>
>> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> -         (dig_port->port != PORT_A)) {
>> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> +                          (dig_port->port != PORT_A))) {
>>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>>               return false;
>>       }
>> @@ -1767,23 +1830,45 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>>               return false;
>>       }
>>
>> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
>> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
>> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
>> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
>> +             return false;
>> +     }
>> +
>>       dev_priv->psr.source_ok = true;
>>       return true;
>>  }
>>
>>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>>  {
>> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>>
>> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
>> -         intel_edp_is_psr_enabled(dev))
>> -             return;
>> +     if (IS_VALLEYVIEW(dev)) {
>> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
>> +                     return;
>> +     } else
>> +             if (intel_edp_is_psr_enabled(dev))
>> +                     return;
>>
>>       /* Enable PSR on the panel */
>> -     intel_edp_psr_enable_sink(intel_dp);
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_enable_sink(intel_dp);
>> +     else
>> +             intel_edp_psr_enable_sink(intel_dp);
>>
>>       /* Enable PSR on the host */
>> -     intel_edp_psr_enable_source(intel_dp);
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_enable_source(intel_dp);
>> +     else
>> +             intel_edp_psr_enable_source(intel_dp);
>> +
>> +     dev_priv->psr.active = true;
>>  }
>>
>>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
>> @@ -1791,16 +1876,43 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>
>> +     if (!is_edp_psr(intel_dp))
>> +             return;
>> +
>>       /* Setup PSR once */
>>       intel_edp_psr_setup(intel_dp);
>>
>>       mutex_lock(&dev_priv->psr.lock);
>> -     if (intel_edp_psr_match_conditions(intel_dp) &&
>> -         !intel_edp_is_psr_enabled(dev))
>> +     if (intel_edp_psr_match_conditions(intel_dp))
>>               intel_edp_psr_do_enable(intel_dp);
>>       mutex_unlock(&dev_priv->psr.lock);
>>  }
>>
>> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
>> +{
>> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_crtc *intel_crtc =
>> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> +     uint32_t val;
>> +
>> +     if (!dev_priv->psr.setup_done)
>> +             return;
>> +
>> +     intel_edp_psr_inactivate(dev, false);
>> +
>> +     if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
>> +                   VLV_EDP_PSR_IN_TRANS) == 0, 250))
>> +             WARN(1, "PSR transition took longer than expected\n");
>> +
>> +     val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
>> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
>> +     val &= ~VLV_EDP_PSR_ENABLE;
>> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> +     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
>> +}
>> +
>>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>>  {
>>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> @@ -1823,6 +1935,7 @@ void intel_edp_psr_update(struct drm_device *dev)
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct intel_encoder *encoder;
>>       struct intel_dp *intel_dp = NULL;
>> +     struct intel_crtc *intel_crtc;
>>
>>       if (!dev_priv->psr.setup_done)
>>               return;
>> @@ -1830,26 +1943,93 @@ void intel_edp_psr_update(struct drm_device *dev)
>>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>>               if (encoder->type == INTEL_OUTPUT_EDP) {
>>                       intel_dp = enc_to_intel_dp(&encoder->base);
>> -
>> -                     if (!is_edp_psr(dev))
>> -                             return;
>> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>>
>>                       mutex_lock(&dev_priv->psr.lock);
>> -                     if (!intel_edp_psr_match_conditions(intel_dp))
>> -                             intel_edp_psr_disable(intel_dp);
>> -                     else
>> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
>> +                             if (IS_VALLEYVIEW(dev))
>> +                                     vlv_edp_psr_disable(intel_dp);
>> +                             else
>> +                                     intel_edp_psr_disable(intel_dp);
>> +                     } else
>>                               if (!intel_edp_is_psr_enabled(dev))
>>                                       intel_edp_psr_do_enable(intel_dp);
>>                       mutex_unlock(&dev_priv->psr.lock);
>>               }
>>  }
>>
>> +void intel_edp_psr_do_inactivate(struct drm_device *dev)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     struct intel_connector *connector;
>> +     struct intel_encoder *encoder;
>> +     struct intel_crtc *intel_crtc;
>> +     struct intel_dp *intel_dp = NULL;
>> +
>> +     list_for_each_entry(connector, &dev->mode_config.connector_list,
>> +                         base.head) {
>> +
>> +             if (connector->base.dpms != DRM_MODE_DPMS_ON)
>> +                     continue;
>> +
>> +             encoder = to_intel_encoder(connector->base.encoder);
>> +             if (encoder->type == INTEL_OUTPUT_EDP) {
>> +
>> +                     intel_dp = enc_to_intel_dp(&encoder->base);
>> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>
> Still digging through the encoder and crtc pointers w/o holding any
> modeset locks. Feels dangerous. intel_edp_psr_match_conditions() does
> the same kind of stuff, and that too now gets called outside modeset
> codepaths.

I don't see an easy way to solve this with current sturcture here
since we need the pipe and intel_dp pointer.
Maybe on the future rework putiing psr inside pipe_config and in a
scruct with all needed info without require to interate anywhere.
But on the current structure I don't see an easy solution, do you?

>> +
>> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
>> +                                                         intel_crtc->pipe))
>> +                             continue;
>> +
>> +                     dev_priv->psr.active = false;
>> +
>> +                     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe),
>> +                                VLV_EDP_PSR_RESET);
>> +                     /* WaClearPSRReset:vlv */
>> +                     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0);
>> +
>> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>> +             }
>> +     }
>> +}
>> +
>> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +
>> +     if (!IS_VALLEYVIEW(dev))
>> +             return;
>> +
>> +     if (!dev_priv->psr.setup_done)
>> +             return;
>> +
>> +     /* If it was requested to not turn psr back delayed work must be
>> +      * canceled even if it is already on inactivated state. */
>> +     if (!schedule_back)
>> +             cancel_delayed_work_sync(&dev_priv->psr.work);
>> +
>> +     if (!dev_priv->psr.active)
>> +             return;
>
> What if psr gets re-activated just after you checked above?

Shouldn't be dangerus... psr.activate idea is to minimize I915_WRITE,
mainly when calling busy ioctls in sequence...
But I'm open to suggestions.

>
>> +
>> +     cancel_delayed_work_sync(&dev_priv->psr.work);
>> +
>> +     intel_edp_psr_do_inactivate(dev);
>> +
>> +     if (schedule_back)
>> +             schedule_delayed_work(&dev_priv->psr.work,
>> +                                   msecs_to_jiffies(5000));
>> +}
>> +
>>  static void intel_disable_dp(struct intel_encoder *encoder)
>>  {
>>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>       enum port port = dp_to_dig_port(intel_dp)->port;
>>       struct drm_device *dev = encoder->base.dev;
>>
>> +     if (IS_VALLEYVIEW(dev))
>> +             vlv_edp_psr_disable(intel_dp);
>> +
>>       /* Make sure the panel is off before trying to change the mode. But also
>>        * ensure that we have vdd while we switch off the panel. */
>>       intel_edp_backlight_off(intel_dp);
>> @@ -1906,6 +2086,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>
>>       intel_edp_backlight_on(intel_dp);
>> +     intel_edp_psr_enable(intel_dp);
>>  }
>>
>>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
>> @@ -3846,8 +4027,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>>               BUG();
>>       }
>>
>> -     if (is_edp(intel_dp))
>> +     if (is_edp(intel_dp)) {
>>               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
>> +             INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
>> +             mutex_init(&dev_priv->psr.lock);
>
> Initializing global state from a per-connector init function seems a bit
> weird.

I thought it as well, but didn't find another place.
My first attempt was at psr_setup, but it is called again after
suspend/resume and it was breaking things up.
suggestions?

>
>> +     }
>>
>>       error = intel_dp_i2c_init(intel_dp, intel_connector, name);
>>       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index 71c1371..d8103f9 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>>  void intel_edp_psr_update(struct drm_device *dev);
>> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back);
>>
>>
>>  /* intel_dsi.c */
>> --
>> 1.8.1.2
>
> --
> Ville Syrjälä
> Intel OTC

Hi Ville, thank you very much for your comments. Coding is improving a
lot along with stability here.
Please help me to get this structure merged than we rework all psr
later to avoid that loop over connectors and encoders....

Thanks,

-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] drm/i915: Add Baytrail PSR Support.
  2014-02-07 18:05                                 ` Rodrigo Vivi
@ 2014-02-07 18:39                                   ` Ville Syrjälä
  0 siblings, 0 replies; 45+ messages in thread
From: Ville Syrjälä @ 2014-02-07 18:39 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Fri, Feb 07, 2014 at 04:05:26PM -0200, Rodrigo Vivi wrote:
> On Fri, Feb 7, 2014 at 3:24 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Wed, Feb 05, 2014 at 05:04:31PM -0200, Rodrigo Vivi wrote:
> >> This patch adds PSR Support to Baytrail.
> >>
> >> Baytrail cannot easily detect screen updates and force PSR exit.
> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy}
> >> and update to enable it back on next display mark_idle.
> >>
> >> v2: Also inactivate PSR on cursor update.
> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
> >>     early on page flip besides avoid initializing inactive/active flag
> >>     more than once.
> >> v4: Fix identation issues.
> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
> >>     support disabled by for now since it isn't working properly yet.
> >> v6: Removing forgotten comment and useless clkgating definition.
> >> v7: Remove inactivate from set_domain. Chris warned this was semanticaly
> >>     wrong.
> >> v8: Accept Ville's suggestions: Use register's names matching spec and
> >>     warn if transition took longer than it should.
> >> v9: New version with delayed work to get PSR back. Disabling it on
> >>     set_domain but not rescheduing it back until next finish_page_flip.
> >>
> >> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
> >> ---
> >>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++-
> >>  drivers/gpu/drm/i915/i915_drv.h      |   5 +-
> >>  drivers/gpu/drm/i915/i915_gem.c      |  12 ++
> >>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++
> >>  drivers/gpu/drm/i915/i915_suspend.c  |   2 +-
> >>  drivers/gpu/drm/i915/intel_display.c |  18 ++-
> >>  drivers/gpu/drm/i915/intel_dp.c      | 256 ++++++++++++++++++++++++++++++-----
> >>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
> >>  8 files changed, 323 insertions(+), 44 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >> index bc8707f..2949c48 100644
> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >>       struct drm_device *dev = node->minor->dev;
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>       u32 psrperf = 0;
> >> +     u32 statA = 0;
> >> +     u32 statB = 0;
> >>       bool enabled = false;
> >>
> >>       intel_runtime_pm_get(dev_priv);
> >> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
> >>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
> >>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
> >>
> >> -     enabled = HAS_PSR(dev) &&
> >> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
> >> +     if (HAS_PSR(dev)) {
> >> +             if (IS_VALLEYVIEW(dev)) {
> >> +                     statA = I915_READ(VLV_PSRSTAT(PIPE_A)) &
> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +                     statB = I915_READ(VLV_PSRSTAT(PIPE_B)) &
> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
> >> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
> >> +             } else
> >> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     }
> >> +     seq_printf(m, "Enabled: %s", yesno(enabled));
> >>
> >> -     if (HAS_PSR(dev))
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> +                     seq_puts(m, " pipe A");
> >> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
> >> +                     seq_puts(m, " pipe B");
> >> +     }
> >> +
> >> +     seq_puts(m, "\n");
> >> +
> >> +     /* VLV PSR has no kind of performance counter */
> >> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
> >>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
> >>                       EDP_PSR_PERF_CNT_MASK;
> >> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
> >> +     }
> >>
> >>       intel_runtime_pm_put(dev_priv);
> >>       return 0;
> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> >> index 21470be..87c346a 100644
> >> --- a/drivers/gpu/drm/i915/i915_drv.h
> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
> >> @@ -747,7 +747,9 @@ struct i915_psr {
> >>       bool sink_support;
> >>       bool source_ok;
> >>       bool setup_done;
> >> +     bool active;
> >>       struct mutex lock;
> >> +     struct delayed_work work;
> >>  };
> >>
> >>  enum intel_pch {
> >> @@ -1867,7 +1869,8 @@ struct drm_i915_file_private {
> >>
> >>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
> >>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
> >> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
> >> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
> >> +                              IS_VALLEYVIEW(dev))
> >>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
> >>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> >> index 39770f7..5ef1380 100644
> >> --- a/drivers/gpu/drm/i915/i915_gem.c
> >> +++ b/drivers/gpu/drm/i915/i915_gem.c
> >> @@ -1256,6 +1256,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
> >>               goto unlock;
> >>       }
> >>
> >> +     /* Here we don't reschedule work to get PSR back because userspace
> >> +     * can set domain and take as much as time it wants to write it.
> >> +     * We only reschedule it back on next finish_page_flip. There is the
> >> +     * risk of PSR be inactive forever depending on how compositor works,
> >> +     * but this is the safest way to avoid loosing screen updates.
> >> +     */
> >> +     intel_edp_psr_inactivate(dev, false);
> >
> > This will still block until PSR is deactivated (aux communication and
> > all). That still seems like a bad idea to do while holding struct_mutex.
> 
> So, what do you suggest here?

Same as before. The disabling could be done from a workqueue.

> 
> >
> >> +
> >>       /* Try to flush the object off the GPU without holding the lock.
> >>        * We will repeat the flush holding the lock in the normal manner
> >>        * to catch cases where we are gazumped.
> >> @@ -1299,6 +1307,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
> >>       if (ret)
> >>               return ret;
> >>
> >> +     intel_edp_psr_inactivate(dev, true);
> >> +
> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >>       if (&obj->base == NULL) {
> >>               ret = -ENOENT;
> >> @@ -4059,6 +4069,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
> >>       if (ret)
> >>               return ret;
> >>
> >> +     intel_edp_psr_inactivate(dev, true);
> >> +
> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
> >>       if (&obj->base == NULL) {
> >>               ret = -ENOENT;
> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> >> index cbbaf26..a5815d0 100644
> >> --- a/drivers/gpu/drm/i915/i915_reg.h
> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
> >> @@ -1968,6 +1968,43 @@
> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
> >>
> >> +/* VLV eDP PSR registers */
> >> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
> >> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
> >> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
> >> +#define  VLV_EDP_PSR_RESET                   (1<<1)
> >> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
> >> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
> >> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
> >> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
> >> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
> >> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
> >> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
> >> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
> >> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
> >> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
> >> +#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
> >> +
> >> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
> >> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
> >> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
> >> +#define VLV_VSCSDP(pipe)     _PIPE(pipe, _VSCSDPA, _VSCSDPB)
> >> +
> >> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
> >> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
> >> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
> >> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
> >> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
> >> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
> >> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
> >> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
> >> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
> >> +#define  VLV_EDP_PSR_EXIT            (5<<0)
> >> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
> >> +#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
> >> +
> >>  /* HSW+ eDP PSR registers */
> >>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
> >>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
> >> diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
> >> index ffcba21..6b31020 100644
> >> --- a/drivers/gpu/drm/i915/i915_suspend.c
> >> +++ b/drivers/gpu/drm/i915/i915_suspend.c
> >> @@ -289,8 +289,8 @@ static void i915_restore_display(struct drm_device *dev)
> >>       }
> >>
> >>       /* Force a full PSR setup on resume */
> >> +     intel_edp_psr_inactivate(dev, false);
> >>       dev_priv->psr.setup_done = false;
> >> -     intel_edp_psr_update(dev);
> >>
> >>       /* only restore FBC info on the platform that supports FBC*/
> >>       intel_disable_fbc(dev);
> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> >> index 1a9aa19..92d6df4 100644
> >> --- a/drivers/gpu/drm/i915/intel_display.c
> >> +++ b/drivers/gpu/drm/i915/intel_display.c
> >> @@ -4451,9 +4451,13 @@ static void intel_connector_check_state(struct intel_connector *connector)
> >>   * consider. */
> >>  void intel_connector_dpms(struct drm_connector *connector, int mode)
> >>  {
> >> +     struct drm_device *dev = connector->dev;
> >> +
> >>       /* All the simple cases only support two dpms states. */
> >> -     if (mode != DRM_MODE_DPMS_ON)
> >> +     if (mode != DRM_MODE_DPMS_ON) {
> >>               mode = DRM_MODE_DPMS_OFF;
> >> +             intel_edp_psr_inactivate(dev, false);
> >
> > Maybe check if this connector even has PSR enabled?
> 
> the psr_inactivate already does that by checking psr.setup_done and psr.active.

I meant that it will now disable PSR for all displays even if the
DPMS mode was changed for some other display. Well, I guess it's
somewhat rare to only do DPMS for a subset of active displays.

> 
> >
> >> +     }
> >>
> >>       if (mode == connector->dpms)
> >>               return;
> >> @@ -7501,6 +7505,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >>       u32 base = 0, pos = 0;
> >>       bool visible;
> >>
> >> +     intel_edp_psr_inactivate(dev, true);
> >
> > Don't need to inactivate unless the cursor is or was visible.
> 
> so, below next retur after check visible and cursor_visible should be
> enough, right?

Yeah that should be fine.

> >
> >> +
> >>       if (on)
> >>               base = intel_crtc->cursor_addr;
> >>
> >> @@ -8230,12 +8236,15 @@ void intel_mark_idle(struct drm_device *dev)
> >>               gen6_rps_idle(dev->dev_private);
> >>  }
> >>
> >> +
> >>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
> >>                       struct intel_ring_buffer *ring)
> >>  {
> >>       struct drm_device *dev = obj->base.dev;
> >>       struct drm_crtc *crtc;
> >>
> >> +     intel_edp_psr_inactivate(dev, true);
> >> +
> >>       if (!i915.powersave)
> >>               return;
> >>
> >> @@ -8336,6 +8345,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
> >>       queue_work(dev_priv->wq, &work->work);
> >>
> >>       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
> >> +
> >> +     /* Get PSR back after set_domain inactivated it without rescheduling
> >> +     * it back. */
> >> +     schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(5000));
> >>  }
> >>
> >>  void intel_finish_page_flip(struct drm_device *dev, int pipe)
> >> @@ -8688,6 +8701,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> >>       if (work == NULL)
> >>               return -ENOMEM;
> >>
> >> +     /* Inactivate PSR early in page flip */
> >> +     intel_edp_psr_inactivate(dev, true);
> >> +
> >>       work->event = event;
> >>       work->crtc = crtc;
> >>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> >> index 80054bb..576c204 100644
> >> --- a/drivers/gpu/drm/i915/intel_dp.c
> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
> >> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> >>       }
> >>  }
> >>
> >> -static bool is_edp_psr(struct drm_device *dev)
> >> +static bool is_edp_psr(struct intel_dp *intel_dp)
> >> +{
> >> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
> >> +}
> >> +
> >> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
> >>  {
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     uint32_t val;
> >>
> >> -     return dev_priv->psr.sink_support;
> >> +     val = I915_READ(VLV_PSRSTAT(pipe)) &
> >> +             VLV_EDP_PSR_CURR_STATE_MASK;
> >> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
> >> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
> >>  }
> >>
> >>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
> >>  {
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>
> >> -     if (!HAS_PSR(dev))
> >> -             return false;
> >> +     if (HAS_PSR(dev)) {
> >> +             if (IS_VALLEYVIEW(dev))
> >> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
> >> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
> >> +             else
> >> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     }
> >>
> >> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
> >> +     return false;
> >>  }
> >>
> >>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >> @@ -1624,32 +1638,60 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
> >>       POSTING_READ(ctl_reg);
> >>  }
> >>
> >> +static void intel_edp_psr_work(struct work_struct *work)
> >> +{
> >> +     struct drm_i915_private *dev_priv =
> >> +             container_of(work, typeof(*dev_priv), psr.work.work);
> >> +     struct drm_device *dev = dev_priv->dev;
> >> +
> >> +     intel_edp_psr_update(dev);
> >> +}
> >> +
> >>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
> >>  {
> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>       struct edp_vsc_psr psr_vsc;
> >> +     uint32_t val;
> >>
> >>       if (dev_priv->psr.setup_done)
> >>               return;
> >>
> >> -     mutex_init(&dev_priv->psr.lock);
> >> -
> >> -     /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> -     memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> -     psr_vsc.sdp_header.HB0 = 0;
> >> -     psr_vsc.sdp_header.HB1 = 0x7;
> >> -     psr_vsc.sdp_header.HB2 = 0x2;
> >> -     psr_vsc.sdp_header.HB3 = 0x8;
> >> -     intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >> -
> >> -     /* Avoid continuous PSR exit by masking memup and hpd */
> >> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             val  = I915_READ(VLV_VSCSDP(PIPE_A));
> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> +             I915_WRITE(VLV_VSCSDP(PIPE_A), val);
> >> +
> >> +             val  = I915_READ(VLV_VSCSDP(PIPE_B));
> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
> >> +             I915_WRITE(VLV_VSCSDP(PIPE_B), val);
> >> +     } else {
> >> +             /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
> >> +             memset(&psr_vsc, 0, sizeof(psr_vsc));
> >> +             psr_vsc.sdp_header.HB0 = 0;
> >> +             psr_vsc.sdp_header.HB1 = 0x7;
> >> +             psr_vsc.sdp_header.HB2 = 0x2;
> >> +             psr_vsc.sdp_header.HB3 = 0x8;
> >> +             intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
> >> +
> >> +             /* Avoid continuous PSR exit by masking memup and hpd */
> >> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
> >> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
> >> +     }
> >>
> >>       dev_priv->psr.setup_done = true;
> >>  }
> >>
> >> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >> +{
> >> +     /* Enable PSR in sink */
> >> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
> >> +                                         DP_PSR_ENABLE);
> >> +}
> >> +
> >>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1680,6 +1722,27 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
> >>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
> >>  }
> >>
> >> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
> >> +{
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >> +
> >> +     uint32_t idle_frames = 1;
> >> +     uint32_t val = 0;
> >> +
> >> +     val |= VLV_EDP_PSR_ENABLE;
> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
> >> +
> >> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
> >> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
> >> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
> >> +
> >> +     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
> >> +}
> >> +
> >>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1721,8 +1784,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >>               return false;
> >>       }
> >>
> >> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> >> -         (dig_port->port != PORT_A)) {
> >> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
> >> +                          (dig_port->port != PORT_A))) {
> >>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
> >>               return false;
> >>       }
> >> @@ -1767,23 +1830,45 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
> >>               return false;
> >>       }
> >>
> >> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
> >> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
> >> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
> >> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
> >> +             return false;
> >> +     }
> >> +
> >>       dev_priv->psr.source_ok = true;
> >>       return true;
> >>  }
> >>
> >>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
> >>  {
> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >>
> >> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
> >> -         intel_edp_is_psr_enabled(dev))
> >> -             return;
> >> +     if (IS_VALLEYVIEW(dev)) {
> >> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
> >> +                     return;
> >> +     } else
> >> +             if (intel_edp_is_psr_enabled(dev))
> >> +                     return;
> >>
> >>       /* Enable PSR on the panel */
> >> -     intel_edp_psr_enable_sink(intel_dp);
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_enable_sink(intel_dp);
> >> +     else
> >> +             intel_edp_psr_enable_sink(intel_dp);
> >>
> >>       /* Enable PSR on the host */
> >> -     intel_edp_psr_enable_source(intel_dp);
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_enable_source(intel_dp);
> >> +     else
> >> +             intel_edp_psr_enable_source(intel_dp);
> >> +
> >> +     dev_priv->psr.active = true;
> >>  }
> >>
> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp)
> >> @@ -1791,16 +1876,43 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>
> >> +     if (!is_edp_psr(intel_dp))
> >> +             return;
> >> +
> >>       /* Setup PSR once */
> >>       intel_edp_psr_setup(intel_dp);
> >>
> >>       mutex_lock(&dev_priv->psr.lock);
> >> -     if (intel_edp_psr_match_conditions(intel_dp) &&
> >> -         !intel_edp_is_psr_enabled(dev))
> >> +     if (intel_edp_psr_match_conditions(intel_dp))
> >>               intel_edp_psr_do_enable(intel_dp);
> >>       mutex_unlock(&dev_priv->psr.lock);
> >>  }
> >>
> >> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
> >> +{
> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_crtc *intel_crtc =
> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
> >> +     uint32_t val;
> >> +
> >> +     if (!dev_priv->psr.setup_done)
> >> +             return;
> >> +
> >> +     intel_edp_psr_inactivate(dev, false);
> >> +
> >> +     if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
> >> +                   VLV_EDP_PSR_IN_TRANS) == 0, 250))
> >> +             WARN(1, "PSR transition took longer than expected\n");
> >> +
> >> +     val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
> >> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
> >> +     val &= ~VLV_EDP_PSR_ENABLE;
> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
> >> +     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
> >> +}
> >> +
> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
> >>  {
> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
> >> @@ -1823,6 +1935,7 @@ void intel_edp_psr_update(struct drm_device *dev)
> >>       struct drm_i915_private *dev_priv = dev->dev_private;
> >>       struct intel_encoder *encoder;
> >>       struct intel_dp *intel_dp = NULL;
> >> +     struct intel_crtc *intel_crtc;
> >>
> >>       if (!dev_priv->psr.setup_done)
> >>               return;
> >> @@ -1830,26 +1943,93 @@ void intel_edp_psr_update(struct drm_device *dev)
> >>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
> >>               if (encoder->type == INTEL_OUTPUT_EDP) {
> >>                       intel_dp = enc_to_intel_dp(&encoder->base);
> >> -
> >> -                     if (!is_edp_psr(dev))
> >> -                             return;
> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
> >>
> >>                       mutex_lock(&dev_priv->psr.lock);
> >> -                     if (!intel_edp_psr_match_conditions(intel_dp))
> >> -                             intel_edp_psr_disable(intel_dp);
> >> -                     else
> >> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
> >> +                             if (IS_VALLEYVIEW(dev))
> >> +                                     vlv_edp_psr_disable(intel_dp);
> >> +                             else
> >> +                                     intel_edp_psr_disable(intel_dp);
> >> +                     } else
> >>                               if (!intel_edp_is_psr_enabled(dev))
> >>                                       intel_edp_psr_do_enable(intel_dp);
> >>                       mutex_unlock(&dev_priv->psr.lock);
> >>               }
> >>  }
> >>
> >> +void intel_edp_psr_do_inactivate(struct drm_device *dev)
> >> +{
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +     struct intel_connector *connector;
> >> +     struct intel_encoder *encoder;
> >> +     struct intel_crtc *intel_crtc;
> >> +     struct intel_dp *intel_dp = NULL;
> >> +
> >> +     list_for_each_entry(connector, &dev->mode_config.connector_list,
> >> +                         base.head) {
> >> +
> >> +             if (connector->base.dpms != DRM_MODE_DPMS_ON)
> >> +                     continue;
> >> +
> >> +             encoder = to_intel_encoder(connector->base.encoder);
> >> +             if (encoder->type == INTEL_OUTPUT_EDP) {
> >> +
> >> +                     intel_dp = enc_to_intel_dp(&encoder->base);
> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
> >
> > Still digging through the encoder and crtc pointers w/o holding any
> > modeset locks. Feels dangerous. intel_edp_psr_match_conditions() does
> > the same kind of stuff, and that too now gets called outside modeset
> > codepaths.
> 
> I don't see an easy way to solve this with current sturcture here
> since we need the pipe and intel_dp pointer.
> Maybe on the future rework putiing psr inside pipe_config and in a
> scruct with all needed info without require to interate anywhere.
> But on the current structure I don't see an easy solution, do you?

Well, if it was done from a workqueue anyway, it could just grab all
modeset locks. Would just need to make sure we wouldn't cause deadlocks
by doing that.

> 
> >> +
> >> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
> >> +                                                         intel_crtc->pipe))
> >> +                             continue;
> >> +
> >> +                     dev_priv->psr.active = false;
> >> +
> >> +                     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe),
> >> +                                VLV_EDP_PSR_RESET);
> >> +                     /* WaClearPSRReset:vlv */
> >> +                     I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), 0);
> >> +
> >> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >> +             }
> >> +     }
> >> +}
> >> +
> >> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back)
> >> +{
> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
> >> +
> >> +     if (!IS_VALLEYVIEW(dev))
> >> +             return;
> >> +
> >> +     if (!dev_priv->psr.setup_done)
> >> +             return;
> >> +
> >> +     /* If it was requested to not turn psr back delayed work must be
> >> +      * canceled even if it is already on inactivated state. */
> >> +     if (!schedule_back)
> >> +             cancel_delayed_work_sync(&dev_priv->psr.work);
> >> +
> >> +     if (!dev_priv->psr.active)
> >> +             return;
> >
> > What if psr gets re-activated just after you checked above?
> 
> Shouldn't be dangerus... psr.activate idea is to minimize I915_WRITE,
> mainly when calling busy ioctls in sequence...
> But I'm open to suggestions.

I think if this did happen and there are no more updates to the
screen for a while, this would leave PSR enabled, with potentially
stale screen contents.

> 
> >
> >> +
> >> +     cancel_delayed_work_sync(&dev_priv->psr.work);
> >> +
> >> +     intel_edp_psr_do_inactivate(dev);
> >> +
> >> +     if (schedule_back)
> >> +             schedule_delayed_work(&dev_priv->psr.work,
> >> +                                   msecs_to_jiffies(5000));
> >> +}
> >> +
> >>  static void intel_disable_dp(struct intel_encoder *encoder)
> >>  {
> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >>       enum port port = dp_to_dig_port(intel_dp)->port;
> >>       struct drm_device *dev = encoder->base.dev;
> >>
> >> +     if (IS_VALLEYVIEW(dev))
> >> +             vlv_edp_psr_disable(intel_dp);
> >> +
> >>       /* Make sure the panel is off before trying to change the mode. But also
> >>        * ensure that we have vdd while we switch off the panel. */
> >>       intel_edp_backlight_off(intel_dp);
> >> @@ -1906,6 +2086,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >>
> >>       intel_edp_backlight_on(intel_dp);
> >> +     intel_edp_psr_enable(intel_dp);
> >>  }
> >>
> >>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
> >> @@ -3846,8 +4027,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> >>               BUG();
> >>       }
> >>
> >> -     if (is_edp(intel_dp))
> >> +     if (is_edp(intel_dp)) {
> >>               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
> >> +             INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
> >> +             mutex_init(&dev_priv->psr.lock);
> >
> > Initializing global state from a per-connector init function seems a bit
> > weird.
> 
> I thought it as well, but didn't find another place.
> My first attempt was at psr_setup, but it is called again after
> suspend/resume and it was breaking things up.
> suggestions?

Some modeset init function sounds like the right place.

> 
> >
> >> +     }
> >>
> >>       error = intel_dp_i2c_init(intel_dp, intel_connector, name);
> >>       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> >> index 71c1371..d8103f9 100644
> >> --- a/drivers/gpu/drm/i915/intel_drv.h
> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> >> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
> >>  void intel_edp_psr_update(struct drm_device *dev);
> >> +void intel_edp_psr_inactivate(struct drm_device *dev, bool schedule_back);
> >>
> >>
> >>  /* intel_dsi.c */
> >> --
> >> 1.8.1.2
> >
> > --
> > Ville Syrjälä
> > Intel OTC
> 
> Hi Ville, thank you very much for your comments. Coding is improving a
> lot along with stability here.
> Please help me to get this structure merged than we rework all psr
> later to avoid that loop over connectors and encoders....
> 
> Thanks,
> 
> -- 
> Rodrigo Vivi
> Blog: http://blog.vivi.eng.br

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH] drm/i915: Add Baytrail PSR Support.
  2014-01-29 14:56               ` Ville Syrjälä
  2014-01-29 15:47                 ` Rodrigo Vivi
  2014-01-29 15:50                 ` Rodrigo Vivi
@ 2014-02-12 16:29                 ` Daniel Vetter
  2 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2014-02-12 16:29 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Wed, Jan 29, 2014 at 3:56 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> I think once we get to working on D0i2, we'll need to move the PSR
> wakeup to happen from a workqueue since it essentially requires a
> full modeset. Even now in your code it's somewhat questionable
> since you're doing stuff like aux transfers while holding
> struct_mutex.

Imo we can fix this up later on by pushing it into a workqueue. It's
not great that we block while hodling struct_mutex, but imo there's
too many loose pieces around psr so I prefer we start by merging
something pessimistic, but known to work properly. Then we can tune
and improve with the knowledge that the crc testcase will catch
regressions.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 2/2] drm/i915: Add Baytrail PSR Support.
  2013-12-17 19:57 [PATCH 1/2] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
@ 2013-12-17 19:57 ` Rodrigo Vivi
  0 siblings, 0 replies; 45+ messages in thread
From: Rodrigo Vivi @ 2013-12-17 19:57 UTC (permalink / raw)
  To: intel-gfx

This patch adds PSR Support to Baytrail.

Baytrail cannot easily detect screen updates and force PSR exit.
So we inactivate it on busy_ioctl and update to get it back
on next display mark_idle.
The current issue with this implementation is the cursor updates.
(Yet to be fixed).

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  18 +++-
 drivers/gpu/drm/i915/i915_drv.h      |   4 +-
 drivers/gpu/drm/i915/i915_gem.c      |   3 +
 drivers/gpu/drm/i915/i915_reg.h      |  34 ++++++++
 drivers/gpu/drm/i915/intel_ddi.c     |   3 +-
 drivers/gpu/drm/i915/intel_display.c |   3 +
 drivers/gpu/drm/i915/intel_dp.c      | 156 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 8 files changed, 191 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 6294ffd..b29543d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1816,6 +1816,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 psrstatus;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -1823,14 +1824,23 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
 	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			     psrstatus = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			enabled = ((psrstatus == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				   (psrstatus == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 	seq_printf(m, "Enabled: %s\n", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	/* VLV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 
 	intel_runtime_pm_put(dev_priv);
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index cae3225..916d243 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -716,6 +716,7 @@ struct i915_psr {
 	bool sink_support;
 	bool source_ok;
 	bool setup_done;
+	bool inactive;
 };
 
 enum intel_pch {
@@ -1851,7 +1852,8 @@ struct drm_i915_file_private {
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev))
 #define HAS_PC8(dev)		(IS_HASWELL(dev)) /* XXX HSW:ULX */
 #define HAS_RUNTIME_PM(dev)	(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 32636a4..d0a5c27 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4048,6 +4048,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		return ret;
 
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_inactivate(dev);
+
 	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 	if (&obj->base == NULL) {
 		ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index e9548b1..c996e261 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1969,6 +1969,40 @@
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* VLV eDP PSR registers */
+#define VLV_EDP_PSR_CTL				(VLV_DISPLAY_BASE + 0x60090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define  VLV_EDP_PSR_INT_TRANSITION		(1<<24)
+
+#define VLV_PIPEA_VSC_SDP_REG		(VLV_DISPLAY_BASE + 0x600a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+
+#define VLV_EDP_PSR_STATUS_CTL		(VLV_DISPLAY_BASE + 0x60094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+
+#define VLV_PSR_CLK_GATE_DISABLE	(VLV_DISPLAY_BASE + 0x6204)
+#define  VLV_CLK_DISABLE_PIPE_B		(1<<30)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 1488b28..ae5a876 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1275,7 +1275,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 			intel_dp_stop_link_train(intel_dp);
 
 		ironlake_edp_backlight_on(intel_dp);
-		intel_edp_psr_enable(intel_dp);
+		if (!IS_VALLEYVIEW(dev))
+			intel_edp_psr_enable(intel_dp);
 	}
 
 	if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 674fd43..9cc7227 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8175,6 +8175,9 @@ void intel_mark_idle(struct drm_device *dev)
 
 	if (dev_priv->info->gen >= 6)
 		gen6_rps_idle(dev->dev_private);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_edp_psr_update(dev);
 }
 
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index f062a59..fd1ade1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1525,11 +1525,19 @@ static bool is_edp_psr(struct drm_device *dev)
 static bool intel_edp_is_psr_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	if (!HAS_PSR(dev))
-		return false;
+	if (HAS_PSR(dev)) {
+		if (IS_VALLEYVIEW(dev)) {
+			val = I915_READ(VLV_EDP_PSR_STATUS_CTL) &
+				VLV_EDP_PSR_CURR_STATE_MASK;
+			return ((val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				(val == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
+		} else
+			return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	}
 
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	return false;
 }
 
 static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
@@ -1566,25 +1574,44 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct edp_vsc_psr psr_vsc;
+	uint32_t val;
 
 	if (dev_priv->psr.setup_done)
 		return;
 
-	/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-	intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+	if (IS_VALLEYVIEW(dev)) {
+		val  = I915_READ(VLV_PIPEA_VSC_SDP_REG);
+		val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+		val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+		I915_WRITE(VLV_PIPEA_VSC_SDP_REG, val);
+
+		val = I915_READ(VLV_PSR_CLK_GATE_DISABLE);
+		val |= VLV_CLK_DISABLE_PIPE_B;
+		I915_WRITE(VLV_PSR_CLK_GATE_DISABLE, val);
+	} else {
+		/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+		memset(&psr_vsc, 0, sizeof(psr_vsc));
+		psr_vsc.sdp_header.HB0 = 0;
+		psr_vsc.sdp_header.HB1 = 0x7;
+		psr_vsc.sdp_header.HB2 = 0x2;
+		psr_vsc.sdp_header.HB3 = 0x8;
+		intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+	}
 
 	dev_priv->psr.setup_done = true;
 }
 
+static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	/* Enable PSR in sink */
+	intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+				    DP_PSR_ENABLE);
+}
+
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1613,6 +1640,24 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
 
+static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t idle_frames = 1;
+	uint32_t val;
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val |= VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+
+	val |= VLV_EDP_PSR_MODE_HW_TIMER;
+	val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
+	val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
+
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
+}
+
 static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1654,8 +1699,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
-	    (dig_port->port != PORT_A)) {
+	if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+			     (dig_port->port != PORT_A))) {
 		DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
 		return false;
 	}
@@ -1707,28 +1752,54 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!intel_edp_psr_match_conditions(intel_dp) ||
-	    intel_edp_is_psr_enabled(dev))
+	if (intel_edp_is_psr_enabled(dev))
 		return;
 
 	/* Setup PSR once */
 	intel_edp_psr_setup(intel_dp);
 
 	/* Enable PSR on the panel */
-	intel_edp_psr_enable_sink(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_sink(intel_dp);
+	else
+		intel_edp_psr_enable_sink(intel_dp);
 
 	/* Enable PSR on the host */
-	intel_edp_psr_enable_source(intel_dp);
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_enable_source(intel_dp);
+	else
+		intel_edp_psr_enable_source(intel_dp);
+
+	dev_priv->psr.inactive = false;
 }
 
 void intel_edp_psr_enable(struct intel_dp *intel_dp)
 {
+	if (intel_edp_psr_match_conditions(intel_dp))
+		intel_edp_psr_do_enable(intel_dp);
+}
+
+void vlv_edp_psr_disable(struct intel_dp *intel_dp)
+{
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL);
 
-	if (intel_edp_psr_match_conditions(intel_dp) &&
-	    !intel_edp_is_psr_enabled(dev))
-		intel_edp_psr_do_enable(intel_dp);
+	if (!dev_priv->psr.setup_done)
+		return;
+
+	intel_edp_psr_inactivate(dev);
+
+	if (val & VLV_EDP_PSR_IN_TRANS)
+		udelay(250);
+
+	val = I915_READ(VLV_EDP_PSR_CTL);
+	val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+	val &= ~VLV_EDP_PSR_ENABLE;
+	val &= ~VLV_EDP_PSR_MODE_MASK;
+	I915_WRITE(VLV_EDP_PSR_CTL, val);
 }
 
 void intel_edp_psr_disable(struct intel_dp *intel_dp)
@@ -1760,20 +1831,52 @@ void intel_edp_psr_update(struct drm_device *dev)
 			if (!is_edp_psr(dev))
 				return;
 
-			if (!intel_edp_psr_match_conditions(intel_dp))
-				intel_edp_psr_disable(intel_dp);
-			else
+			if (!intel_edp_psr_match_conditions(intel_dp)) {
+				if (IS_VALLEYVIEW(dev))
+					vlv_edp_psr_disable(intel_dp);
+				else
+					intel_edp_psr_disable(intel_dp);
+			} else
 				if (!intel_edp_is_psr_enabled(dev))
 					intel_edp_psr_do_enable(intel_dp);
 		}
 }
 
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp = NULL;
+
+	if (dev_priv->psr.inactive)
+		return;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			intel_dp = enc_to_intel_dp(&encoder->base);
+
+			if (!is_edp_psr(dev))
+				return;
+
+			dev_priv->psr.inactive = true;
+
+			I915_WRITE(VLV_EDP_PSR_CTL, VLV_EDP_PSR_RESET);
+			I915_WRITE(VLV_EDP_PSR_CTL, 0);
+			POSTING_READ(VLV_EDP_PSR_CTL);
+
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		}
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct drm_device *dev = encoder->base.dev;
 
+	if (IS_VALLEYVIEW(dev))
+		vlv_edp_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	ironlake_edp_backlight_off(intel_dp);
@@ -1830,6 +1933,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	ironlake_edp_backlight_on(intel_dp);
+	intel_edp_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -3703,6 +3807,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	     error, port_name(port));
 
 	dev_priv->psr.setup_done = false;
+	dev_priv->psr.inactive = true;
 
 	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
 		i2c_del_adapter(&intel_dp->adapter);
@@ -3734,6 +3839,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void
 intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_digital_port *intel_dig_port;
 	struct intel_encoder *intel_encoder;
 	struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f7b5b2f..6c6e1cd 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -730,6 +730,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
+void intel_edp_psr_inactivate(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2014-02-12 16:29 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-23 18:16 [PATCH 1/4] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
2014-01-23 18:16 ` [PATCH 2/4] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
2014-01-24 14:50   ` Ville Syrjälä
2014-01-24 16:02     ` Rodrigo Vivi
2014-01-23 18:16 ` [PATCH 3/4] drm/i915: Update PSR on resume Rodrigo Vivi
2014-02-05 19:04   ` [PATCH 1/2] " Rodrigo Vivi
2014-01-23 18:16 ` [PATCH 4/4] drm/i915: Add Baytrail PSR Support Rodrigo Vivi
2014-01-23 19:19   ` [PATCH] " Rodrigo Vivi
2014-01-24 14:53     ` Ville Syrjälä
2014-01-24 16:05       ` Rodrigo Vivi
2014-01-24 17:41         ` Ville Syrjälä
2014-01-28 19:47           ` [PATCH 4/4] " Rodrigo Vivi
2014-01-29 12:47             ` [PATCH] " Rodrigo Vivi
2014-01-29 13:12               ` Chris Wilson
2014-01-29 13:24                 ` Rodrigo Vivi
2014-01-29 13:27                   ` Chris Wilson
2014-01-29 13:54                     ` Rodrigo Vivi
2014-01-29 14:02                       ` Chris Wilson
2014-01-29 14:23                         ` Rodrigo Vivi
2014-01-29 14:26                           ` Chris Wilson
2014-01-29 19:20                             ` Daniel Vetter
2014-01-29 14:55                 ` Rodrigo Vivi
2014-01-29 19:21                   ` Daniel Vetter
2014-02-01 11:34                     ` Chris Wilson
2014-02-04 10:49                       ` Daniel Vetter
2014-01-29 14:56               ` Ville Syrjälä
2014-01-29 15:47                 ` Rodrigo Vivi
2014-01-29 16:38                   ` Ville Syrjälä
2014-01-29 17:48                     ` Rodrigo Vivi
2014-01-29 18:24                       ` Ville Syrjälä
2014-01-29 15:50                 ` Rodrigo Vivi
2014-01-30 13:02                   ` Chris Wilson
2014-01-30 17:01                     ` Rodrigo Vivi
2014-02-04 10:53                       ` Daniel Vetter
2014-02-04 13:03                         ` Rodrigo Vivi
2014-02-04 13:54                           ` Daniel Vetter
2014-02-05 19:04                             ` [PATCH 2/2] " Rodrigo Vivi
2014-02-07 17:24                               ` Ville Syrjälä
2014-02-07 18:05                                 ` Rodrigo Vivi
2014-02-07 18:39                                   ` Ville Syrjälä
2014-02-12 16:29                 ` [PATCH] " Daniel Vetter
2014-01-23 19:19 ` [PATCH] drm/i915: Set primary plane enable at dpcntrl Rodrigo Vivi
2014-01-24 14:58   ` Ville Syrjälä
2014-01-28 19:46     ` [PATCH 1/4] " Rodrigo Vivi
  -- strict thread matches above, loose matches on Subject: below --
2013-12-17 19:57 [PATCH 1/2] drm/i915: move psr_setup_done to psr struct Rodrigo Vivi
2013-12-17 19:57 ` [PATCH 2/2] drm/i915: Add Baytrail PSR Support Rodrigo Vivi

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.