[PATCH 09/14] drm/i915/dsb: Introduce intel_dsb_wait_scanline_{in, out}()
Manna, Animesh
animesh.manna at intel.com
Wed Jul 3 11:37:33 UTC 2024
> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces at lists.freedesktop.org> On Behalf Of Ville
> Syrjala
> Sent: Tuesday, June 25, 2024 12:40 AM
> To: intel-gfx at lists.freedesktop.org
> Subject: [PATCH 09/14] drm/i915/dsb: Introduce
> intel_dsb_wait_scanline_{in, out}()
>
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> Add functions to emit a DSB scanline window wait instructions.
> We can either wait for the scanline to be IN the window or OUT of the
> window.
>
> The hardware doesn't handle wraparound so we must manually deal with it
> by swapping the IN range to the inverse OUT range, or vice versa.
>
> Also add a bit of paranoia to catch the edge case of waiting for the entire
> frame. That doesn't make sense since an IN wait would be a nop, and an
> OUT wait would imply waiting forever. Most of the time this also results in
> both scanline ranges (original and inverted) to have lower=upper+1 which is
> nonsense from the hw POV.
>
> For now we are only handling the case where the scanline wait happens prior
> to latching the double buffered registers during the commit (which might
> change the timings due to LRR/VRR/etc.)
>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_dsb.c | 73 ++++++++++++++++++++++++
> drivers/gpu/drm/i915/display/intel_dsb.h | 6 ++
> 2 files changed, 79 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c
> b/drivers/gpu/drm/i915/display/intel_dsb.c
> index 81937908c798..092cf082ac39 100644
> --- a/drivers/gpu/drm/i915/display/intel_dsb.c
> +++ b/drivers/gpu/drm/i915/display/intel_dsb.c
> @@ -362,6 +362,79 @@ void intel_dsb_nonpost_end(struct intel_dsb *dsb)
> intel_dsb_noop(dsb, 4);
> }
>
> +static void intel_dsb_emit_wait_dsl(struct intel_dsb *dsb,
> + u32 opcode, int lower, int upper) {
> + u64 window = ((u64)upper << DSB_SCANLINE_UPPER_SHIFT) |
> + ((u64)lower << DSB_SCANLINE_LOWER_SHIFT);
> +
> + intel_dsb_emit(dsb, lower_32_bits(window),
> + (opcode << DSB_OPCODE_SHIFT) |
> + upper_32_bits(window));
> +}
> +
> +static void intel_dsb_wait_dsl(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int lower_in, int upper_in,
Lower/upper keyword maybe confusing for during intel_dsb_wait_scanline_out(), maybe good to have name like in_start and in_end, similarly out_start and out_end.
> + int lower_out, int upper_out) {
> + struct intel_crtc *crtc = dsb->crtc;
> +
> + lower_in = dsb_scanline_to_hw(state, crtc, lower_in);
> + upper_in = dsb_scanline_to_hw(state, crtc, upper_in);
> +
> + lower_out = dsb_scanline_to_hw(state, crtc, lower_out);
> + upper_out = dsb_scanline_to_hw(state, crtc, upper_out);
If lower_in > upper_in, then calculation for lower_out and upper_out is not needed. Even before calling dsb_scanline_to_hw() we can compare and check if it is for scanline_in or scanline_out... rt?
Regards,
Animesh
> +
> + if (upper_in >= lower_in)
> + intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_IN,
> + lower_in, upper_in);
> + else if (upper_out >= lower_out)
> + intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT,
> + lower_out, upper_out);
> + else
> + drm_WARN_ON(crtc->base.dev, 1); /* assert_dsl_ok() should
> have caught
> +it already */ }
> +
> +static void assert_dsl_ok(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int start, int end)
> +{
> + struct intel_crtc *crtc = dsb->crtc;
> + int vtotal = dsb_vtotal(state, crtc);
> +
> + /*
> + * Waiting for the entire frame doesn't make sense,
> + * (IN==don't wait, OUT=wait forever).
> + */
> + drm_WARN(crtc->base.dev, (end - start + vtotal) % vtotal == vtotal -
> 1,
> + "[CRTC:%d:%s] DSB %d bad scanline window wait: %d-%d
> (vt=%d)\n",
> + crtc->base.base.id, crtc->base.name, dsb->id,
> + start, end, vtotal);
> +}
> +
> +void intel_dsb_wait_scanline_in(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int start, int end)
> +{
> + assert_dsl_ok(state, dsb, start, end);
> +
> + intel_dsb_wait_dsl(state, dsb,
> + start, end,
> + end + 1, start - 1);
> +}
> +
> +void intel_dsb_wait_scanline_out(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int start, int end)
> +{
> + assert_dsl_ok(state, dsb, start, end);
> +
> + intel_dsb_wait_dsl(state, dsb,
> + end + 1, start - 1,
> + start, end);
> +}
> +
> static void intel_dsb_align_tail(struct intel_dsb *dsb) {
> u32 aligned_tail, tail;
> diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h
> b/drivers/gpu/drm/i915/display/intel_dsb.h
> index 84fc2f8434d1..d0737cefb393 100644
> --- a/drivers/gpu/drm/i915/display/intel_dsb.h
> +++ b/drivers/gpu/drm/i915/display/intel_dsb.h
> @@ -39,6 +39,12 @@ void intel_dsb_reg_write_masked(struct intel_dsb
> *dsb, void intel_dsb_noop(struct intel_dsb *dsb, int count); void
> intel_dsb_nonpost_start(struct intel_dsb *dsb); void
> intel_dsb_nonpost_end(struct intel_dsb *dsb);
> +void intel_dsb_wait_scanline_in(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int lower, int upper);
> +void intel_dsb_wait_scanline_out(struct intel_atomic_state *state,
> + struct intel_dsb *dsb,
> + int lower, int upper);
>
> void intel_dsb_commit(struct intel_dsb *dsb,
> bool wait_for_vblank);
> --
> 2.44.2
More information about the Intel-gfx
mailing list