Skip to content

Commit 51e0395

Browse files
committed
drm/i915/dsb: Allow intel_dsb_chain() to use DSB_WAIT_FOR_VBLANK
Allow intel_dsb_chain() to start the chained DSB at start of the undelaye vblank. This is slightly more involved than simply setting the bit as we must use the DEwake mechanism to eliminate pkgC latency. And DSB_ENABLE_DEWAKE itself is problematic in that it allows us to configure just a single scanline, and if the current scanline is already past that DSB_ENABLE_DEWAKE won't do anything, rendering the whole thing moot. The current workaround involves checking the pipe's current scanline with the CPU, and if it looks like we're about to miss the configured DEwake scanline we set DSB_FORCE_DEWAKE to immediately assert DEwake. This is somewhat racy since the hardware is making progress all the while we're checking it on the CPU. We can make things less racy by chaining two DSBs and handling the DSB_FORCE_DEWAKE stuff entirely without CPU involvement: 1. CPU starts the first DSB immediately 2. First DSB configures the second DSB, including its dewake_scanline 3. First DSB starts the second w/ DSB_WAIT_FOR_VBLANK 4. First DSB asserts DSB_FORCE_DEWAKE 5. First DSB waits until we're outside the dewake_scanline-vblank_start window 6. First DSB deasserts DSB_FORCE_DEWAKE That will guarantee that the we are fully awake when the second DSB starts to actually execute. 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 06358cc commit 51e0395

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

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

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ static int dsb_vtotal(struct intel_atomic_state *state,
130130
return intel_mode_vtotal(&crtc_state->hw.adjusted_mode);
131131
}
132132

133-
static int dsb_dewake_scanline(struct intel_atomic_state *state,
134-
struct intel_crtc *crtc)
133+
static int dsb_dewake_scanline_start(struct intel_atomic_state *state,
134+
struct intel_crtc *crtc)
135135
{
136136
const struct intel_crtc_state *crtc_state = pre_commit_crtc_state(state, crtc);
137137
struct drm_i915_private *i915 = to_i915(state->base.dev);
@@ -141,6 +141,14 @@ static int dsb_dewake_scanline(struct intel_atomic_state *state,
141141
intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, latency);
142142
}
143143

144+
static int dsb_dewake_scanline_end(struct intel_atomic_state *state,
145+
struct intel_crtc *crtc)
146+
{
147+
const struct intel_crtc_state *crtc_state = pre_commit_crtc_state(state, crtc);
148+
149+
return intel_mode_vdisplay(&crtc_state->hw.adjusted_mode);
150+
}
151+
144152
static int dsb_scanline_to_hw(struct intel_atomic_state *state,
145153
struct intel_crtc *crtc, int scanline)
146154
{
@@ -527,19 +535,44 @@ static void _intel_dsb_chain(struct intel_atomic_state *state,
527535
dsb_error_int_status(display) | DSB_PROG_INT_STATUS |
528536
dsb_error_int_en(display));
529537

538+
if (ctrl & DSB_WAIT_FOR_VBLANK) {
539+
int dewake_scanline = dsb_dewake_scanline_start(state, crtc);
540+
int hw_dewake_scanline = dsb_scanline_to_hw(state, crtc, dewake_scanline);
541+
542+
intel_dsb_reg_write(dsb, DSB_PMCTRL(pipe, chained_dsb->id),
543+
DSB_ENABLE_DEWAKE |
544+
DSB_SCANLINE_FOR_DEWAKE(hw_dewake_scanline));
545+
}
546+
530547
intel_dsb_reg_write(dsb, DSB_HEAD(pipe, chained_dsb->id),
531548
intel_dsb_buffer_ggtt_offset(&chained_dsb->dsb_buf));
532549

533550
intel_dsb_reg_write(dsb, DSB_TAIL(pipe, chained_dsb->id),
534551
intel_dsb_buffer_ggtt_offset(&chained_dsb->dsb_buf) + tail);
552+
553+
if (ctrl & DSB_WAIT_FOR_VBLANK) {
554+
/*
555+
* Keep DEwake alive via the first DSB, in
556+
* case we're already past dewake_scanline,
557+
* and thus DSB_ENABLE_DEWAKE on the second
558+
* DSB won't do its job.
559+
*/
560+
intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(pipe, dsb->id),
561+
DSB_FORCE_DEWAKE, DSB_FORCE_DEWAKE);
562+
563+
intel_dsb_wait_scanline_out(state, dsb,
564+
dsb_dewake_scanline_start(state, crtc),
565+
dsb_dewake_scanline_end(state, crtc));
566+
}
535567
}
536568

537569
void intel_dsb_chain(struct intel_atomic_state *state,
538570
struct intel_dsb *dsb,
539-
struct intel_dsb *chained_dsb)
571+
struct intel_dsb *chained_dsb,
572+
bool wait_for_vblank)
540573
{
541574
_intel_dsb_chain(state, dsb, chained_dsb,
542-
0);
575+
wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0);
543576
}
544577

545578
static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl,
@@ -697,7 +730,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state,
697730

698731
dsb->chicken = dsb_chicken(state, crtc);
699732
dsb->hw_dewake_scanline =
700-
dsb_scanline_to_hw(state, crtc, dsb_dewake_scanline(state, crtc));
733+
dsb_scanline_to_hw(state, crtc, dsb_dewake_scanline_start(state, crtc));
701734

702735
return dsb;
703736

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ void intel_dsb_wait_scanline_out(struct intel_atomic_state *state,
4747
int lower, int upper);
4848
void intel_dsb_chain(struct intel_atomic_state *state,
4949
struct intel_dsb *dsb,
50-
struct intel_dsb *chained_dsb);
50+
struct intel_dsb *chained_dsb,
51+
bool wait_for_vblank);
5152

5253
void intel_dsb_commit(struct intel_dsb *dsb,
5354
bool wait_for_vblank);

0 commit comments

Comments
 (0)