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;
> + }
> +
> +