Skip to content

Commit 2039809

Browse files
committed
drm/i915/dsb: Introduce intel_dsb_wait_scanline_{in,out}()
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ä <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Reviewed-by: Animesh Manna <[email protected]>
1 parent 8d5ac8e commit 2039809

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

drivers/gpu/drm/i915/display/intel_dsb.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,79 @@ void intel_dsb_nonpost_end(struct intel_dsb *dsb)
362362
intel_dsb_noop(dsb, 4);
363363
}
364364

365+
static void intel_dsb_emit_wait_dsl(struct intel_dsb *dsb,
366+
u32 opcode, int lower, int upper)
367+
{
368+
u64 window = ((u64)upper << DSB_SCANLINE_UPPER_SHIFT) |
369+
((u64)lower << DSB_SCANLINE_LOWER_SHIFT);
370+
371+
intel_dsb_emit(dsb, lower_32_bits(window),
372+
(opcode << DSB_OPCODE_SHIFT) |
373+
upper_32_bits(window));
374+
}
375+
376+
static void intel_dsb_wait_dsl(struct intel_atomic_state *state,
377+
struct intel_dsb *dsb,
378+
int lower_in, int upper_in,
379+
int lower_out, int upper_out)
380+
{
381+
struct intel_crtc *crtc = dsb->crtc;
382+
383+
lower_in = dsb_scanline_to_hw(state, crtc, lower_in);
384+
upper_in = dsb_scanline_to_hw(state, crtc, upper_in);
385+
386+
lower_out = dsb_scanline_to_hw(state, crtc, lower_out);
387+
upper_out = dsb_scanline_to_hw(state, crtc, upper_out);
388+
389+
if (upper_in >= lower_in)
390+
intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_IN,
391+
lower_in, upper_in);
392+
else if (upper_out >= lower_out)
393+
intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT,
394+
lower_out, upper_out);
395+
else
396+
drm_WARN_ON(crtc->base.dev, 1); /* assert_dsl_ok() should have caught it already */
397+
}
398+
399+
static void assert_dsl_ok(struct intel_atomic_state *state,
400+
struct intel_dsb *dsb,
401+
int start, int end)
402+
{
403+
struct intel_crtc *crtc = dsb->crtc;
404+
int vtotal = dsb_vtotal(state, crtc);
405+
406+
/*
407+
* Waiting for the entire frame doesn't make sense,
408+
* (IN==don't wait, OUT=wait forever).
409+
*/
410+
drm_WARN(crtc->base.dev, (end - start + vtotal) % vtotal == vtotal - 1,
411+
"[CRTC:%d:%s] DSB %d bad scanline window wait: %d-%d (vt=%d)\n",
412+
crtc->base.base.id, crtc->base.name, dsb->id,
413+
start, end, vtotal);
414+
}
415+
416+
void intel_dsb_wait_scanline_in(struct intel_atomic_state *state,
417+
struct intel_dsb *dsb,
418+
int start, int end)
419+
{
420+
assert_dsl_ok(state, dsb, start, end);
421+
422+
intel_dsb_wait_dsl(state, dsb,
423+
start, end,
424+
end + 1, start - 1);
425+
}
426+
427+
void intel_dsb_wait_scanline_out(struct intel_atomic_state *state,
428+
struct intel_dsb *dsb,
429+
int start, int end)
430+
{
431+
assert_dsl_ok(state, dsb, start, end);
432+
433+
intel_dsb_wait_dsl(state, dsb,
434+
end + 1, start - 1,
435+
start, end);
436+
}
437+
365438
static void intel_dsb_align_tail(struct intel_dsb *dsb)
366439
{
367440
u32 aligned_tail, tail;

drivers/gpu/drm/i915/display/intel_dsb.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ void intel_dsb_reg_write_masked(struct intel_dsb *dsb,
3939
void intel_dsb_noop(struct intel_dsb *dsb, int count);
4040
void intel_dsb_nonpost_start(struct intel_dsb *dsb);
4141
void intel_dsb_nonpost_end(struct intel_dsb *dsb);
42+
void intel_dsb_wait_scanline_in(struct intel_atomic_state *state,
43+
struct intel_dsb *dsb,
44+
int lower, int upper);
45+
void intel_dsb_wait_scanline_out(struct intel_atomic_state *state,
46+
struct intel_dsb *dsb,
47+
int lower, int upper);
4248

4349
void intel_dsb_commit(struct intel_dsb *dsb,
4450
bool wait_for_vblank);

0 commit comments

Comments
 (0)