[Intel-gfx] [PATCH] drm/i915: Add Baytrail PSR Support.
Rodrigo Vivi
rodrigo.vivi at gmail.com
Wed Jan 29 15:55:35 CET 2014
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 at chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi at 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
More information about the Intel-gfx
mailing list