>-----Original Message-----
>From: Intel-gfx [mailto:intel-gfx-boun...@lists.freedesktop.org] On Behalf Of 
>Rodrigo Vivi
>Sent: Friday, November 14, 2014 10:22 PM
>To: intel-gfx@lists.freedesktop.org
>Cc: Vivi, Rodrigo
>Subject: [Intel-gfx] [PATCH 02/15] drm/i915: Introduce intel_psr.c
>
>No functional changes. Just cleaning and reorganizing it.
>
>v2: Rebase it puting it to begin of psr rework. This helps to blame easily
>at least latest changes.
>
>Signed-off-by: Rodrigo Vivi <rodrigo.v...@intel.com>
>---
> drivers/gpu/drm/i915/Makefile            |   1 +
> drivers/gpu/drm/i915/intel_ddi.c         |   4 +-
> drivers/gpu/drm/i915/intel_display.c     |   2 +-
> drivers/gpu/drm/i915/intel_dp.c          | 381 +----------------------------
> drivers/gpu/drm/i915/intel_drv.h         |  21 +-
> drivers/gpu/drm/i915/intel_frontbuffer.c |   4 +-
> drivers/gpu/drm/i915/intel_psr.c         | 408 +++++++++++++++++++++++++++++++
> 7 files changed, 428 insertions(+), 393 deletions(-)
> create mode 100644 drivers/gpu/drm/i915/intel_psr.c
>
>diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>index 891e584..e4083e4 100644
>--- a/drivers/gpu/drm/i915/Makefile
>+++ b/drivers/gpu/drm/i915/Makefile
>@@ -51,6 +51,7 @@ i915-y += intel_audio.o \
>         intel_frontbuffer.o \
>         intel_modes.o \
>         intel_overlay.o \
>+        intel_psr.o \
>         intel_sideband.o \
>         intel_sprite.o
> i915-$(CONFIG_ACPI)           += intel_acpi.o intel_opregion.o
>diff --git a/drivers/gpu/drm/i915/intel_ddi.c 
>b/drivers/gpu/drm/i915/intel_ddi.c
>index 68703ce..a5a8acd 100644
>--- a/drivers/gpu/drm/i915/intel_ddi.c
>+++ b/drivers/gpu/drm/i915/intel_ddi.c
>@@ -1228,7 +1228,7 @@ static void intel_enable_ddi(struct intel_encoder 
>*intel_encoder)
>                       intel_dp_stop_link_train(intel_dp);
>
>               intel_edp_backlight_on(intel_dp);
>-              intel_edp_psr_enable(intel_dp);
>+              intel_psr_enable(intel_dp);
>       }
>
>       if (intel_crtc->config.has_audio) {
>@@ -1254,7 +1254,7 @@ static void intel_disable_ddi(struct intel_encoder 
>*intel_encoder)
>       if (type == INTEL_OUTPUT_EDP) {
>               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
>
>-              intel_edp_psr_disable(intel_dp);
>+              intel_psr_disable(intel_dp);
>               intel_edp_backlight_off(intel_dp);
>       }
> }
>diff --git a/drivers/gpu/drm/i915/intel_display.c 
>b/drivers/gpu/drm/i915/intel_display.c
>index 4706856..2ca6939 100644
>--- a/drivers/gpu/drm/i915/intel_display.c
>+++ b/drivers/gpu/drm/i915/intel_display.c
>@@ -12310,7 +12310,7 @@ static void intel_setup_outputs(struct drm_device *dev)
>       if (SUPPORTS_TV(dev))
>               intel_tv_init(dev);
>
>-      intel_edp_psr_init(dev);
>+      intel_psr_init(dev);
>
>       for_each_intel_encoder(dev, encoder) {
>               encoder->base.possible_crtcs = encoder->crtc_mask;
>diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>index 01834cd..98f7ecd 100644
>--- a/drivers/gpu/drm/i915/intel_dp.c
>+++ b/drivers/gpu/drm/i915/intel_dp.c
>@@ -2066,385 +2066,6 @@ static void intel_dp_get_config(struct intel_encoder 
>*encoder,
>       }
> }
>
>-static bool is_edp_psr(struct intel_dp *intel_dp)
>-{
>-      return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>-}
>-
>-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;
>-
>-      return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>-}
>-
>-static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>-                                  struct edp_vsc_psr *vsc_psr)
>-{
>-      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>-      struct drm_device *dev = dig_port->base.base.dev;
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
>-      u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
>-      u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
>-      uint32_t *data = (uint32_t *) vsc_psr;
>-      unsigned int i;
>-
>-      /* As per BSPec (Pipe Video Data Island Packet), we need to disable
>-         the video DIP being updated before program video DIP data buffer
>-         registers for DIP being updated. */
>-      I915_WRITE(ctl_reg, 0);
>-      POSTING_READ(ctl_reg);
>-
>-      for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
>-              if (i < sizeof(struct edp_vsc_psr))
>-                      I915_WRITE(data_reg + i, *data++);
>-              else
>-                      I915_WRITE(data_reg + i, 0);
>-      }
>-
>-      I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
>-      POSTING_READ(ctl_reg);
>-}
>-
>-static void intel_edp_psr_setup_vsc(struct intel_dp *intel_dp)
>-{
>-      struct edp_vsc_psr psr_vsc;
>-
>-      /* 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);
>-}
>-
>-static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>-{
>-      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>-      struct drm_device *dev = dig_port->base.base.dev;
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      uint32_t aux_clock_divider;
>-      int precharge = 0x3;
>-      bool only_standby = false;
>-      static const uint8_t aux_msg[] = {
>-              [0] = DP_AUX_NATIVE_WRITE << 4,
>-              [1] = DP_SET_POWER >> 8,
>-              [2] = DP_SET_POWER & 0xff,
>-              [3] = 1 - 1,
>-              [4] = DP_SET_POWER_D0,
>-      };
>-      int i;
>-
>-      BUILD_BUG_ON(sizeof(aux_msg) > 20);
>-
>-      aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
>-
>-      if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
>-              only_standby = true;
>-
>-      /* Enable PSR in sink */
>-      if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby)
>-              drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
>-                                 DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
>-      else
>-              drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
>-                                 DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
>-
>-      /* Setup AUX registers */
>-      for (i = 0; i < sizeof(aux_msg); i += 4)
>-              I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
>-                         intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
>-
>-      I915_WRITE(EDP_PSR_AUX_CTL(dev),
>-                 DP_AUX_CH_CTL_TIME_OUT_400us |
>-                 (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
>-                 (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
>-                 (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>-}
>-
>-static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>-{
>-      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>-      struct drm_device *dev = dig_port->base.base.dev;
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      uint32_t max_sleep_time = 0x1f;
>-      uint32_t idle_frames = 1;
>-      uint32_t val = 0x0;
>-      const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
>-      bool only_standby = false;
>-
>-      if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
>-              only_standby = true;
>-
>-      if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) {
>-              val |= EDP_PSR_LINK_STANDBY;
>-              val |= EDP_PSR_TP2_TP3_TIME_0us;
>-              val |= EDP_PSR_TP1_TIME_0us;
>-              val |= EDP_PSR_SKIP_AUX_EXIT;
>-              val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0;
>-      } else
>-              val |= EDP_PSR_LINK_DISABLE;
>-
>-      I915_WRITE(EDP_PSR_CTL(dev), val |
>-                 (IS_BROADWELL(dev) ? 0 : link_entry_time) |
>-                 max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
>-                 idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
>-                 EDP_PSR_ENABLE);
>-}
>-
>-static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>-{
>-      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>-      struct drm_device *dev = dig_port->base.base.dev;
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      struct drm_crtc *crtc = dig_port->base.base.crtc;
>-      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>-
>-      lockdep_assert_held(&dev_priv->psr.lock);
>-      WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
>-      WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
>-
>-      dev_priv->psr.source_ok = false;
>-
>-      if (IS_HASWELL(dev) && dig_port->port != PORT_A) {
>-              DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>-              return false;
>-      }
>-
>-      if (!i915.enable_psr) {
>-              DRM_DEBUG_KMS("PSR disable by flag\n");
>-              return false;
>-      }
>-
>-      /* Below limitations aren't valid for Broadwell */
>-      if (IS_BROADWELL(dev))
>-              goto out;
>-
>-      if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
>-          S3D_ENABLE) {
>-              DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
>-              return false;
>-      }
>-
>-      if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
>-              DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
>-              return false;
>-      }
>-
>- out:
>-      dev_priv->psr.source_ok = true;
>-      return true;
>-}
>-
>-static void intel_edp_psr_do_enable(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;
>-
>-      WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>-      WARN_ON(dev_priv->psr.active);
>-      lockdep_assert_held(&dev_priv->psr.lock);
>-
>-      /* Enable/Re-enable PSR on the host */
>-      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);
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-
>-      if (!HAS_PSR(dev)) {
>-              DRM_DEBUG_KMS("PSR not supported on this platform\n");
>-              return;
>-      }
>-
>-      if (!is_edp_psr(intel_dp)) {
>-              DRM_DEBUG_KMS("PSR not supported by this panel\n");
>-              return;
>-      }
>-
>-      mutex_lock(&dev_priv->psr.lock);
>-      if (dev_priv->psr.enabled) {
>-              DRM_DEBUG_KMS("PSR already in use\n");
>-              goto unlock;
>-      }
>-
>-      if (!intel_edp_psr_match_conditions(intel_dp))
>-              goto unlock;
>-
>-      dev_priv->psr.busy_frontbuffer_bits = 0;
>-
>-      intel_edp_psr_setup_vsc(intel_dp);
>-
>-      /* 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);
>-
>-      /* Enable PSR on the panel */
>-      intel_edp_psr_enable_sink(intel_dp);
>-
>-      dev_priv->psr.enabled = intel_dp;
>-unlock:
>-      mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-void intel_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;
>-
>-      mutex_lock(&dev_priv->psr.lock);
>-      if (!dev_priv->psr.enabled) {
>-              mutex_unlock(&dev_priv->psr.lock);
>-              return;
>-      }
>-
>-      if (dev_priv->psr.active) {
>-              I915_WRITE(EDP_PSR_CTL(dev),
>-                         I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
>-
>-              /* Wait till PSR is idle */
>-              if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
>-                             EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
>-                      DRM_ERROR("Timed out waiting for PSR Idle State\n");
>-
>-              dev_priv->psr.active = false;
>-      } else {
>-              WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>-      }
>-
>-      dev_priv->psr.enabled = NULL;
>-      mutex_unlock(&dev_priv->psr.lock);
>-
>-      cancel_delayed_work_sync(&dev_priv->psr.work);
>-}
>-
>-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 intel_dp *intel_dp = dev_priv->psr.enabled;
>-
>-      /* We have to make sure PSR is ready for re-enable
>-       * otherwise it keeps disabled until next full enable/disable cycle.
>-       * PSR might take some time to get fully disabled
>-       * and be ready for re-enable.
>-       */
>-      if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
>-                    EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
>-              DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
>-              return;
>-      }
>-
>-      mutex_lock(&dev_priv->psr.lock);
>-      intel_dp = dev_priv->psr.enabled;
>-
>-      if (!intel_dp)
>-              goto unlock;
>-
>-      /*
>-       * The delayed work can race with an invalidate hence we need to
>-       * recheck. Since psr_flush first clears this and then reschedules we
>-       * won't ever miss a flush when bailing out here.
>-       */
>-      if (dev_priv->psr.busy_frontbuffer_bits)
>-              goto unlock;
>-
>-      intel_edp_psr_do_enable(intel_dp);
>-unlock:
>-      mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-static void intel_edp_psr_do_exit(struct drm_device *dev)
>-{
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-
>-      if (dev_priv->psr.active) {
>-              u32 val = I915_READ(EDP_PSR_CTL(dev));
>-
>-              WARN_ON(!(val & EDP_PSR_ENABLE));
>-
>-              I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
>-
>-              dev_priv->psr.active = false;
>-      }
>-
>-}
>-
>-void intel_edp_psr_invalidate(struct drm_device *dev,
>-                            unsigned frontbuffer_bits)
>-{
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      struct drm_crtc *crtc;
>-      enum pipe pipe;
>-
>-      mutex_lock(&dev_priv->psr.lock);
>-      if (!dev_priv->psr.enabled) {
>-              mutex_unlock(&dev_priv->psr.lock);
>-              return;
>-      }
>-
>-      crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc;
>-      pipe = to_intel_crtc(crtc)->pipe;
>-
>-      intel_edp_psr_do_exit(dev);
>-
>-      frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
>-
>-      dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
>-      mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-void intel_edp_psr_flush(struct drm_device *dev,
>-                       unsigned frontbuffer_bits)
>-{
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-      struct drm_crtc *crtc;
>-      enum pipe pipe;
>-
>-      mutex_lock(&dev_priv->psr.lock);
>-      if (!dev_priv->psr.enabled) {
>-              mutex_unlock(&dev_priv->psr.lock);
>-              return;
>-      }
>-
>-      crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc;
>-      pipe = to_intel_crtc(crtc)->pipe;
>-      dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
>-
>-      /*
>-       * On Haswell sprite plane updates don't result in a psr invalidating
>-       * signal in the hardware. Which means we need to manually fake this in
>-       * software for all flushes, not just when we've seen a preceding
>-       * invalidation through frontbuffer rendering.
>-       */
>-      if (IS_HASWELL(dev) &&
>-          (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
>-              intel_edp_psr_do_exit(dev);
>-
>-      if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
>-              schedule_delayed_work(&dev_priv->psr.work,
>-                                    msecs_to_jiffies(100));
>-      mutex_unlock(&dev_priv->psr.lock);
>-}
>-
>-void intel_edp_psr_init(struct drm_device *dev)
>-{
>-      struct drm_i915_private *dev_priv = dev->dev_private;
>-
>-      INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
>-      mutex_init(&dev_priv->psr.lock);
>-}
>-
> static void intel_disable_dp(struct intel_encoder *encoder)
> {
>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>@@ -5115,7 +4736,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int 
>refresh_rate)
>        * hard to tell without seeing the user of this function of this code.
>        * Check locking and ordering once that lands.
>        */
>-      if (INTEL_INFO(dev)->gen < 8 && intel_edp_is_psr_enabled(dev)) {
>+      if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {

Shouldn't we do <= 8 to cover CHV ?

Also, I see that we are converting the 'static' _is_enabled function into a
non-static (exported) one and use 'psr.enabled' variable. (patch 9/15)
In this case, shouldn't we protect this function using psr.lock ?
[actually a comment on patch 9/15, but the caller is here]

Thanks,
Durga

>               DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
>               return;
>       }
>diff --git a/drivers/gpu/drm/i915/intel_drv.h 
>b/drivers/gpu/drm/i915/intel_drv.h
>index 8432ae2..ccfee9c 100644
>--- a/drivers/gpu/drm/i915/intel_drv.h
>+++ b/drivers/gpu/drm/i915/intel_drv.h
>@@ -996,21 +996,16 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp);
> void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
> void intel_edp_panel_on(struct intel_dp *intel_dp);
> 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_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
>-void intel_edp_psr_invalidate(struct drm_device *dev,
>-                            unsigned frontbuffer_bits);
>-void intel_edp_psr_flush(struct drm_device *dev,
>-                       unsigned frontbuffer_bits);
>-void intel_edp_psr_init(struct drm_device *dev);
>-
> void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector 
> *connector);
> void intel_dp_mst_suspend(struct drm_device *dev);
> void intel_dp_mst_resume(struct drm_device *dev);
> int intel_dp_max_link_bw(struct intel_dp *intel_dp);
> void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
>+uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
>+void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
>+
> /* intel_dp_mst.c */
> int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int 
> conn_id);
> void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
>@@ -1114,6 +1109,16 @@ void intel_backlight_register(struct drm_device *dev);
> void intel_backlight_unregister(struct drm_device *dev);
>
>
>+/* intel_psr.c */
>+bool intel_psr_is_enabled(struct drm_device *dev);
>+void intel_psr_enable(struct intel_dp *intel_dp);
>+void intel_psr_disable(struct intel_dp *intel_dp);
>+void intel_psr_invalidate(struct drm_device *dev,
>+                            unsigned frontbuffer_bits);
>+void intel_psr_flush(struct drm_device *dev,
>+                       unsigned frontbuffer_bits);
>+void intel_psr_init(struct drm_device *dev);
>+
> /* intel_runtime_pm.c */
> int intel_power_domains_init(struct drm_i915_private *);
> void intel_power_domains_fini(struct drm_i915_private *);
>diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c 
>b/drivers/gpu/drm/i915/intel_frontbuffer.c
>index 58cf2e6..79f6d72 100644
>--- a/drivers/gpu/drm/i915/intel_frontbuffer.c
>+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
>@@ -156,7 +156,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object 
>*obj,
>
>       intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
>
>-      intel_edp_psr_invalidate(dev, obj->frontbuffer_bits);
>+      intel_psr_invalidate(dev, obj->frontbuffer_bits);
> }
>
> /**
>@@ -182,7 +182,7 @@ void intel_frontbuffer_flush(struct drm_device *dev,
>
>       intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
>
>-      intel_edp_psr_flush(dev, frontbuffer_bits);
>+      intel_psr_flush(dev, frontbuffer_bits);
>
>       /*
>        * FIXME: Unconditional fbc flushing here is a rather gross hack and
>diff --git a/drivers/gpu/drm/i915/intel_psr.c 
>b/drivers/gpu/drm/i915/intel_psr.c
>new file mode 100644
>index 0000000..7b3ed91
>--- /dev/null
>+++ b/drivers/gpu/drm/i915/intel_psr.c
>@@ -0,0 +1,408 @@
>+/*
>+ * Copyright © 2014 Intel Corporation
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a
>+ * copy of this software and associated documentation files (the "Software"),
>+ * to deal in the Software without restriction, including without limitation
>+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>+ * and/or sell copies of the Software, and to permit persons to whom the
>+ * Software is furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice (including the next
>+ * paragraph) shall be included in all copies or substantial portions of the
>+ * Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>+ * DEALINGS IN THE SOFTWARE.
>+ */
>+
>+#include <drm/drmP.h>
>+
>+#include "intel_drv.h"
>+#include "i915_drv.h"
>+
>+static bool is_edp_psr(struct intel_dp *intel_dp)
>+{
>+      return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>+}
>+
>+bool intel_psr_is_enabled(struct drm_device *dev)
>+{
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+      if (!HAS_PSR(dev))
>+              return false;
>+
>+      return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>+}
>+
>+static void intel_psr_write_vsc(struct intel_dp *intel_dp,
>+                                  struct edp_vsc_psr *vsc_psr)
>+{
>+      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>+      struct drm_device *dev = dig_port->base.base.dev;
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
>+      u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
>+      u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
>+      uint32_t *data = (uint32_t *) vsc_psr;
>+      unsigned int i;
>+
>+      /* As per BSPec (Pipe Video Data Island Packet), we need to disable
>+         the video DIP being updated before program video DIP data buffer
>+         registers for DIP being updated. */
>+      I915_WRITE(ctl_reg, 0);
>+      POSTING_READ(ctl_reg);
>+
>+      for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
>+              if (i < sizeof(struct edp_vsc_psr))
>+                      I915_WRITE(data_reg + i, *data++);
>+              else
>+                      I915_WRITE(data_reg + i, 0);
>+      }
>+
>+      I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
>+      POSTING_READ(ctl_reg);
>+}
>+
>+static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
>+{
>+      struct edp_vsc_psr psr_vsc;
>+
>+      /* 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_psr_write_vsc(intel_dp, &psr_vsc);
>+}
>+
>+static void intel_psr_enable_sink(struct intel_dp *intel_dp)
>+{
>+      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>+      struct drm_device *dev = dig_port->base.base.dev;
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      uint32_t aux_clock_divider;
>+      int precharge = 0x3;
>+      bool only_standby = false;
>+      static const uint8_t aux_msg[] = {
>+              [0] = DP_AUX_NATIVE_WRITE << 4,
>+              [1] = DP_SET_POWER >> 8,
>+              [2] = DP_SET_POWER & 0xff,
>+              [3] = 1 - 1,
>+              [4] = DP_SET_POWER_D0,
>+      };
>+      int i;
>+
>+      BUILD_BUG_ON(sizeof(aux_msg) > 20);
>+
>+      aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
>+
>+      if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
>+              only_standby = true;
>+
>+      /* Enable PSR in sink */
>+      if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby)
>+              drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
>+                                 DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
>+      else
>+              drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
>+                                 DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
>+
>+      /* Setup AUX registers */
>+      for (i = 0; i < sizeof(aux_msg); i += 4)
>+              I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
>+                         intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
>+
>+      I915_WRITE(EDP_PSR_AUX_CTL(dev),
>+                 DP_AUX_CH_CTL_TIME_OUT_400us |
>+                 (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
>+                 (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
>+                 (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>+}
>+
>+static void intel_psr_enable_source(struct intel_dp *intel_dp)
>+{
>+      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>+      struct drm_device *dev = dig_port->base.base.dev;
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      uint32_t max_sleep_time = 0x1f;
>+      uint32_t idle_frames = 1;
>+      uint32_t val = 0x0;
>+      const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
>+      bool only_standby = false;
>+
>+      if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
>+              only_standby = true;
>+
>+      if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) {
>+              val |= EDP_PSR_LINK_STANDBY;
>+              val |= EDP_PSR_TP2_TP3_TIME_0us;
>+              val |= EDP_PSR_TP1_TIME_0us;
>+              val |= EDP_PSR_SKIP_AUX_EXIT;
>+              val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0;
>+      } else
>+              val |= EDP_PSR_LINK_DISABLE;
>+
>+      I915_WRITE(EDP_PSR_CTL(dev), val |
>+                 (IS_BROADWELL(dev) ? 0 : link_entry_time) |
>+                 max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
>+                 idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
>+                 EDP_PSR_ENABLE);
>+}
>+
>+static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
>+{
>+      struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>+      struct drm_device *dev = dig_port->base.base.dev;
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      struct drm_crtc *crtc = dig_port->base.base.crtc;
>+      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>+
>+      lockdep_assert_held(&dev_priv->psr.lock);
>+      WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
>+      WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
>+
>+      dev_priv->psr.source_ok = false;
>+
>+      if (IS_HASWELL(dev) && dig_port->port != PORT_A) {
>+              DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>+              return false;
>+      }
>+
>+      if (!i915.enable_psr) {
>+              DRM_DEBUG_KMS("PSR disable by flag\n");
>+              return false;
>+      }
>+
>+      /* Below limitations aren't valid for Broadwell */
>+      if (IS_BROADWELL(dev))
>+              goto out;
>+
>+      if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
>+          S3D_ENABLE) {
>+              DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
>+              return false;
>+      }
>+
>+      if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
>+              DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
>+              return false;
>+      }
>+
>+ out:
>+      dev_priv->psr.source_ok = true;
>+      return true;
>+}
>+
>+static void intel_psr_do_enable(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;
>+
>+      WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>+      WARN_ON(dev_priv->psr.active);
>+      lockdep_assert_held(&dev_priv->psr.lock);
>+
>+      /* Enable/Re-enable PSR on the host */
>+      intel_psr_enable_source(intel_dp);
>+
>+      dev_priv->psr.active = true;
>+}
>+
>+void intel_psr_enable(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;
>+
>+      if (!HAS_PSR(dev)) {
>+              DRM_DEBUG_KMS("PSR not supported on this platform\n");
>+              return;
>+      }
>+
>+      if (!is_edp_psr(intel_dp)) {
>+              DRM_DEBUG_KMS("PSR not supported by this panel\n");
>+              return;
>+      }
>+
>+      mutex_lock(&dev_priv->psr.lock);
>+      if (dev_priv->psr.enabled) {
>+              DRM_DEBUG_KMS("PSR already in use\n");
>+              goto unlock;
>+      }
>+
>+      if (!intel_psr_match_conditions(intel_dp))
>+              goto unlock;
>+
>+      dev_priv->psr.busy_frontbuffer_bits = 0;
>+
>+      intel_psr_setup_vsc(intel_dp);
>+
>+      /* 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);
>+
>+      /* Enable PSR on the panel */
>+      intel_psr_enable_sink(intel_dp);
>+
>+      dev_priv->psr.enabled = intel_dp;
>+unlock:
>+      mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+void intel_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;
>+
>+      mutex_lock(&dev_priv->psr.lock);
>+      if (!dev_priv->psr.enabled) {
>+              mutex_unlock(&dev_priv->psr.lock);
>+              return;
>+      }
>+
>+      if (dev_priv->psr.active) {
>+              I915_WRITE(EDP_PSR_CTL(dev),
>+                         I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
>+
>+              /* Wait till PSR is idle */
>+              if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
>+                             EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
>+                      DRM_ERROR("Timed out waiting for PSR Idle State\n");
>+
>+              dev_priv->psr.active = false;
>+      } else {
>+              WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
>+      }
>+
>+      dev_priv->psr.enabled = NULL;
>+      mutex_unlock(&dev_priv->psr.lock);
>+
>+      cancel_delayed_work_sync(&dev_priv->psr.work);
>+}
>+
>+static void intel_psr_work(struct work_struct *work)
>+{
>+      struct drm_i915_private *dev_priv =
>+              container_of(work, typeof(*dev_priv), psr.work.work);
>+      struct intel_dp *intel_dp = dev_priv->psr.enabled;
>+
>+      /* We have to make sure PSR is ready for re-enable
>+       * otherwise it keeps disabled until next full enable/disable cycle.
>+       * PSR might take some time to get fully disabled
>+       * and be ready for re-enable.
>+       */
>+      if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
>+                    EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
>+              DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
>+              return;
>+      }
>+
>+      mutex_lock(&dev_priv->psr.lock);
>+      intel_dp = dev_priv->psr.enabled;
>+
>+      if (!intel_dp)
>+              goto unlock;
>+
>+      /*
>+       * The delayed work can race with an invalidate hence we need to
>+       * recheck. Since psr_flush first clears this and then reschedules we
>+       * won't ever miss a flush when bailing out here.
>+       */
>+      if (dev_priv->psr.busy_frontbuffer_bits)
>+              goto unlock;
>+
>+      intel_psr_do_enable(intel_dp);
>+unlock:
>+      mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+static void intel_psr_exit(struct drm_device *dev)
>+{
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+      if (dev_priv->psr.active) {
>+              u32 val = I915_READ(EDP_PSR_CTL(dev));
>+
>+              WARN_ON(!(val & EDP_PSR_ENABLE));
>+
>+              I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
>+
>+              dev_priv->psr.active = false;
>+      }
>+
>+}
>+
>+void intel_psr_invalidate(struct drm_device *dev,
>+                            unsigned frontbuffer_bits)
>+{
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      struct drm_crtc *crtc;
>+      enum pipe pipe;
>+
>+      mutex_lock(&dev_priv->psr.lock);
>+      if (!dev_priv->psr.enabled) {
>+              mutex_unlock(&dev_priv->psr.lock);
>+              return;
>+      }
>+
>+      crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc;
>+      pipe = to_intel_crtc(crtc)->pipe;
>+
>+      intel_psr_exit(dev);
>+
>+      frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
>+
>+      dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
>+      mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+void intel_psr_flush(struct drm_device *dev,
>+                       unsigned frontbuffer_bits)
>+{
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+      struct drm_crtc *crtc;
>+      enum pipe pipe;
>+
>+      mutex_lock(&dev_priv->psr.lock);
>+      if (!dev_priv->psr.enabled) {
>+              mutex_unlock(&dev_priv->psr.lock);
>+              return;
>+      }
>+
>+      crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc;
>+      pipe = to_intel_crtc(crtc)->pipe;
>+      dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
>+
>+      /*
>+       * On Haswell sprite plane updates don't result in a psr invalidating
>+       * signal in the hardware. Which means we need to manually fake this in
>+       * software for all flushes, not just when we've seen a preceding
>+       * invalidation through frontbuffer rendering.
>+       */
>+      if (IS_HASWELL(dev) &&
>+          (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
>+              intel_psr_exit(dev);
>+
>+      if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
>+              schedule_delayed_work(&dev_priv->psr.work,
>+                                    msecs_to_jiffies(100));
>+      mutex_unlock(&dev_priv->psr.lock);
>+}
>+
>+void intel_psr_init(struct drm_device *dev)
>+{
>+      struct drm_i915_private *dev_priv = dev->dev_private;
>+
>+      INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work);
>+      mutex_init(&dev_priv->psr.lock);
>+}
>--
>1.9.3
>
>_______________________________________________
>Intel-gfx mailing list
>Intel-gfx@lists.freedesktop.org
>http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to