This patch just introduce registers and functions for PSR Baytrail.

It is important to highlight this patch doesn't work alone.
Baytrail PSR has some critical PSR-exit trigger issues that are fixed
on following patches.
Also, only on last one we mark baytrail/valleyview as HAS_PSR.

Cc: Ville Syrjälä <ville.syrj...@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.v...@gmail.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   5 ++
 drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++++
 drivers/gpu/drm/i915/intel_display.c |   2 +
 drivers/gpu/drm/i915/intel_dp.c      | 151 +++++++++++++++++++++++++++++++----
 drivers/gpu/drm/i915/intel_drv.h     |   1 +
 5 files changed, 179 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c5abff7..18f457e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -779,10 +779,15 @@ struct i915_fbc {
        } no_fbc_reason;
 };
 
+struct intel_dp;
+
 struct i915_psr {
        bool sink_support;
        bool source_ok;
        bool setup_done;
+       void (*setup)(struct intel_dp *intel_dp);
+       void (*enable_sink)(struct intel_dp *intel_dp);
+       void (*enable_source)(struct intel_dp *intel_dp);
 };
 
 enum intel_pch {
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2f564ce..d6b203f 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1984,6 +1984,43 @@
 #define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
 #define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
 
+/* 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 e23ff4c..26196b8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10533,6 +10533,8 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
+       intel_edp_psr_init(dev);
+
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) 
{
                encoder->base.possible_crtcs = encoder->crtc_mask;
                encoder->base.possible_clones =
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 0799882..aabab25 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1610,14 +1610,30 @@ 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;
+
+       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,
@@ -1649,6 +1665,29 @@ static void intel_edp_psr_write_vsc(struct intel_dp 
*intel_dp,
        POSTING_READ(ctl_reg);
 }
 
+static void vlv_edp_psr_setup(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;
+       uint32_t val;
+
+       if (dev_priv->psr.setup_done)
+               return;
+
+       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);
+
+       dev_priv->psr.setup_done = true;
+}
+
 static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1673,6 +1712,13 @@ static void intel_edp_psr_setup(struct intel_dp 
*intel_dp)
        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);
@@ -1703,6 +1749,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);
@@ -1739,8 +1806,8 @@ static bool intel_edp_psr_match_conditions(struct 
intel_dp *intel_dp)
 
        dev_priv->psr.source_ok = 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;
        }
@@ -1791,22 +1858,30 @@ 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 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);
+       dev_priv->psr.enable_sink(intel_dp);
 
        /* Enable PSR on the host */
-       intel_edp_psr_enable_source(intel_dp);
+       dev_priv->psr.enable_source(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;
 
        if (!HAS_PSR(dev)) {
                DRM_DEBUG_KMS("PSR not supported on this platform\n");
@@ -1819,13 +1894,35 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
        }
 
        /* Setup PSR once */
-       intel_edp_psr_setup(intel_dp);
+       dev_priv->psr.setup(intel_dp);
 
-       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;
+
+       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);
@@ -1860,13 +1957,33 @@ void intel_edp_psr_update(struct drm_device *dev)
                        intel_dp = enc_to_intel_dp(&encoder->base);
 
                        if (!intel_edp_psr_match_conditions(intel_dp))
-                               intel_edp_psr_disable(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);
+                               intel_edp_psr_do_enable(intel_dp);
                }
 }
 
+void intel_edp_psr_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!HAS_PSR(dev))
+               return;
+
+       if (IS_VALLEYVIEW(dev)) {
+               dev_priv->psr.setup = vlv_edp_psr_setup;
+               dev_priv->psr.enable_sink = vlv_edp_psr_enable_sink;
+               dev_priv->psr.enable_source = vlv_edp_psr_enable_source;
+       } else {
+               dev_priv->psr.setup = intel_edp_psr_setup;
+               dev_priv->psr.enable_sink = intel_edp_psr_enable_sink;
+               dev_priv->psr.enable_source = intel_edp_psr_enable_source;
+       }
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 180d602..2e4516d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -757,6 +757,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_init(struct drm_device *dev);
 
 
 /* intel_dsi.c */
-- 
1.8.3.1

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

Reply via email to