Re: [Intel-gfx] [PATCH v4 10/11] drm/i915: move pipe update code into crtc.

2020-12-16 Thread Ville Syrjälä
On Wed, Dec 16, 2020 at 01:29:17PM +0200, Jani Nikula wrote:
> From: Dave Airlie 
> 
> Daniel suggested this should move here.

Slightly better than where it is now I guess. I'd kinda like to put it
next to its callers but not sure that wouldn't end up in a mess.

Reviewed-by: Ville Syrjälä 

> 
> Signed-off-by: Dave Airlie 
> Signed-off-by: Jani Nikula 
> ---
>  drivers/gpu/drm/i915/display/intel_crtc.c   | 230 
>  drivers/gpu/drm/i915/display/intel_sprite.c | 228 ---
>  2 files changed, 230 insertions(+), 228 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c 
> b/drivers/gpu/drm/i915/display/intel_crtc.c
> index 0161e18f1a50..9010c55bbc4e 100644
> --- a/drivers/gpu/drm/i915/display/intel_crtc.c
> +++ b/drivers/gpu/drm/i915/display/intel_crtc.c
> @@ -10,6 +10,9 @@
>  #include 
>  #include 
>  
> +#include "i915_trace.h"
> +#include "i915_vgpu.h"
> +
>  #include "intel_atomic.h"
>  #include "intel_atomic_plane.h"
>  #include "intel_color.h"
> @@ -17,7 +20,9 @@
>  #include "intel_cursor.h"
>  #include "intel_display_debugfs.h"
>  #include "intel_display_types.h"
> +#include "intel_dsi.h"
>  #include "intel_pipe_crc.h"
> +#include "intel_psr.h"
>  #include "intel_sprite.h"
>  
>  /* Primary plane formats for gen <= 3 */
> @@ -955,3 +960,228 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, 
> enum pipe pipe)
>  
>   return ret;
>  }
> +
> +int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
> +  int usecs)
> +{
> + /* paranoia */
> + if (!adjusted_mode->crtc_htotal)
> + return 1;
> +
> + return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock,
> + 1000 * adjusted_mode->crtc_htotal);
> +}
> +
> +/**
> + * intel_pipe_update_start() - start update of a set of display registers
> + * @new_crtc_state: the new crtc state
> + *
> + * Mark the start of an update to pipe registers that should be updated
> + * atomically regarding vblank. If the next vblank will happens within
> + * the next 100 us, this function waits until the vblank passes.
> + *
> + * After a successful call to this function, interrupts will be disabled
> + * until a subsequent call to intel_pipe_update_end(). That is done to
> + * avoid random delays.
> + */
> +void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
> +{
> + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
> + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> + const struct drm_display_mode *adjusted_mode = 
> _crtc_state->hw.adjusted_mode;
> + long timeout = msecs_to_jiffies_timeout(1);
> + int scanline, min, max, vblank_start;
> + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(>base);
> + bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || 
> IS_CHERRYVIEW(dev_priv)) &&
> + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
> + DEFINE_WAIT(wait);
> + u32 psr_status;
> +
> + if (new_crtc_state->uapi.async_flip)
> + return;
> +
> + vblank_start = adjusted_mode->crtc_vblank_start;
> + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
> + vblank_start = DIV_ROUND_UP(vblank_start, 2);
> +
> + /* FIXME needs to be calibrated sensibly */
> + min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
> +   VBLANK_EVASION_TIME_US);
> + max = vblank_start - 1;
> +
> + if (min <= 0 || max <= 0)
> + goto irq_disable;
> +
> + if (drm_WARN_ON(_priv->drm, drm_crtc_vblank_get(>base)))
> + goto irq_disable;
> +
> + /*
> +  * Wait for psr to idle out after enabling the VBL interrupts
> +  * VBL interrupts will start the PSR exit and prevent a PSR
> +  * re-entry as well.
> +  */
> + if (intel_psr_wait_for_idle(new_crtc_state, _status))
> + drm_err(_priv->drm,
> + "PSR idle timed out 0x%x, atomic update may fail\n",
> + psr_status);
> +
> + local_irq_disable();
> +
> + crtc->debug.min_vbl = min;
> + crtc->debug.max_vbl = max;
> + trace_intel_pipe_update_start(crtc);
> +
> + for (;;) {
> + /*
> +  * prepare_to_wait() has a memory barrier, which guarantees
> +  * other CPUs can see the task state update by the time we
> +  * read the scanline.
> +  */
> + prepare_to_wait(wq, , TASK_UNINTERRUPTIBLE);
> +
> + scanline = intel_get_crtc_scanline(crtc);
> + if (scanline < min || scanline > max)
> + break;
> +
> + if (!timeout) {
> + drm_err(_priv->drm,
> + "Potential atomic update failure on pipe %c\n",
> + pipe_name(crtc->pipe));
> + break;
> + }
> +
> + 

[Intel-gfx] [PATCH v4 10/11] drm/i915: move pipe update code into crtc.

2020-12-16 Thread Jani Nikula
From: Dave Airlie 

Daniel suggested this should move here.

Signed-off-by: Dave Airlie 
Signed-off-by: Jani Nikula 
---
 drivers/gpu/drm/i915/display/intel_crtc.c   | 230 
 drivers/gpu/drm/i915/display/intel_sprite.c | 228 ---
 2 files changed, 230 insertions(+), 228 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c 
b/drivers/gpu/drm/i915/display/intel_crtc.c
index 0161e18f1a50..9010c55bbc4e 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -10,6 +10,9 @@
 #include 
 #include 
 
+#include "i915_trace.h"
+#include "i915_vgpu.h"
+
 #include "intel_atomic.h"
 #include "intel_atomic_plane.h"
 #include "intel_color.h"
@@ -17,7 +20,9 @@
 #include "intel_cursor.h"
 #include "intel_display_debugfs.h"
 #include "intel_display_types.h"
+#include "intel_dsi.h"
 #include "intel_pipe_crc.h"
+#include "intel_psr.h"
 #include "intel_sprite.h"
 
 /* Primary plane formats for gen <= 3 */
@@ -955,3 +960,228 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, 
enum pipe pipe)
 
return ret;
 }
+
+int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+int usecs)
+{
+   /* paranoia */
+   if (!adjusted_mode->crtc_htotal)
+   return 1;
+
+   return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock,
+   1000 * adjusted_mode->crtc_htotal);
+}
+
+/**
+ * intel_pipe_update_start() - start update of a set of display registers
+ * @new_crtc_state: the new crtc state
+ *
+ * Mark the start of an update to pipe registers that should be updated
+ * atomically regarding vblank. If the next vblank will happens within
+ * the next 100 us, this function waits until the vblank passes.
+ *
+ * After a successful call to this function, interrupts will be disabled
+ * until a subsequent call to intel_pipe_update_end(). That is done to
+ * avoid random delays.
+ */
+void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
+{
+   struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+   struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+   const struct drm_display_mode *adjusted_mode = 
_crtc_state->hw.adjusted_mode;
+   long timeout = msecs_to_jiffies_timeout(1);
+   int scanline, min, max, vblank_start;
+   wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(>base);
+   bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || 
IS_CHERRYVIEW(dev_priv)) &&
+   intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
+   DEFINE_WAIT(wait);
+   u32 psr_status;
+
+   if (new_crtc_state->uapi.async_flip)
+   return;
+
+   vblank_start = adjusted_mode->crtc_vblank_start;
+   if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+   vblank_start = DIV_ROUND_UP(vblank_start, 2);
+
+   /* FIXME needs to be calibrated sensibly */
+   min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
+ VBLANK_EVASION_TIME_US);
+   max = vblank_start - 1;
+
+   if (min <= 0 || max <= 0)
+   goto irq_disable;
+
+   if (drm_WARN_ON(_priv->drm, drm_crtc_vblank_get(>base)))
+   goto irq_disable;
+
+   /*
+* Wait for psr to idle out after enabling the VBL interrupts
+* VBL interrupts will start the PSR exit and prevent a PSR
+* re-entry as well.
+*/
+   if (intel_psr_wait_for_idle(new_crtc_state, _status))
+   drm_err(_priv->drm,
+   "PSR idle timed out 0x%x, atomic update may fail\n",
+   psr_status);
+
+   local_irq_disable();
+
+   crtc->debug.min_vbl = min;
+   crtc->debug.max_vbl = max;
+   trace_intel_pipe_update_start(crtc);
+
+   for (;;) {
+   /*
+* prepare_to_wait() has a memory barrier, which guarantees
+* other CPUs can see the task state update by the time we
+* read the scanline.
+*/
+   prepare_to_wait(wq, , TASK_UNINTERRUPTIBLE);
+
+   scanline = intel_get_crtc_scanline(crtc);
+   if (scanline < min || scanline > max)
+   break;
+
+   if (!timeout) {
+   drm_err(_priv->drm,
+   "Potential atomic update failure on pipe %c\n",
+   pipe_name(crtc->pipe));
+   break;
+   }
+
+   local_irq_enable();
+
+   timeout = schedule_timeout(timeout);
+
+   local_irq_disable();
+   }
+
+   finish_wait(wq, );
+
+   drm_crtc_vblank_put(>base);
+
+   /*
+* On VLV/CHV DSI the scanline counter would appear to
+* increment approx. 1/3 of a scanline before start of vblank.
+* The registers still get latched at start