From patchwork Wed Jan 29 15:50:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rodrigo Vivi X-Patchwork-Id: 3552011 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 367EA9F382 for ; Wed, 29 Jan 2014 15:50:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5E5BB200DF for ; Wed, 29 Jan 2014 15:50:19 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id A504A201BB for ; Wed, 29 Jan 2014 15:50:17 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DFAA6FCE60; Wed, 29 Jan 2014 07:50:14 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-pd0-f178.google.com (mail-pd0-f178.google.com [209.85.192.178]) by gabe.freedesktop.org (Postfix) with ESMTP id 1D76DFCDC3 for ; Wed, 29 Jan 2014 07:50:12 -0800 (PST) Received: by mail-pd0-f178.google.com with SMTP id y13so1848678pdi.9 for ; Wed, 29 Jan 2014 07:50:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=F56L0enEjyVU8z08t85eygMsQMMz+qdZ08r4o/JZ+NI=; b=DpugW6f/5ObkLhXXC4rY56QJ/tccSKVQQUiXiIqnetgC9A3KL7QaIsIwT6BOFkC8ya UolfwxwKeHB4EVzHvQ79XEvqCzAIJD/iojqzbY+0VJx93ncvOjaaDxT4ItiQMwPbAjs6 4SvHivF/WSlYyi0u0mURdv5DDnGJLN092Gex5dFPy/KHzt4W5UsYXPeWRJQq0lGDVUpo rx/1Rg1D6TJyNZyjCf7RekFEUHBCdm6mHWz034ucEtVQZOtEGrBqVZrfpEfGjEvjN9jC JfsZpiCEm48kt7pUEkZVYqTEuNwwhj2awwxy2L21vJdg964VBE2FFxiH7xq63tt+ecja zRcA== X-Received: by 10.66.139.8 with SMTP id qu8mr8657803pab.157.1391010611772; Wed, 29 Jan 2014 07:50:11 -0800 (PST) Received: from localhost ([134.134.139.76]) by mx.google.com with ESMTPSA id nu10sm8358295pbb.16.2014.01.29.07.50.09 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Jan 2014 07:50:10 -0800 (PST) From: Rodrigo Vivi To: intel-gfx@lists.freedesktop.org Date: Wed, 29 Jan 2014 13:50:06 -0200 Message-Id: <1391010606-9206-1-git-send-email-rodrigo.vivi@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <20140129145648.GE9454@intel.com> References: <20140129145648.GE9454@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH] drm/i915: Add Baytrail PSR Support. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi --- 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 */