drm/i915/dsb: Account for VRR properly in DSB scanline stuff

When determining various scanlines for DSB use we should take into
account whether VRR is active at the time when the DSB uses said
scanline information. For now all DSB scanline usage occurs prior
to the actual commit, so we only need to care about the state of
VRR at that time.

I've decided to move intel_crtc_scanline_to_hw() in its entirety
to the DSB code as it will also need to know the actual state
of VRR in order to do its job 100% correctly.

TODO: figure out how much of this could be moved to some
      more generic place and perhaps be shared with the CPU
      vblank evasion code/etc...

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240624191032.27333-8-ville.syrjala@linux.intel.com
Reviewed-by: Animesh Manna <animesh.manna@intel.com>
This commit is contained in:
Ville Syrjälä 2024-06-24 22:10:25 +03:00
parent eb4556f25f
commit a69dcaf931
5 changed files with 67 additions and 18 deletions

View File

@ -1032,8 +1032,8 @@ static bool intel_crtc_vrr_enabling(struct intel_atomic_state *state,
vrr_params_changed(old_crtc_state, new_crtc_state)));
}
static bool intel_crtc_vrr_disabling(struct intel_atomic_state *state,
struct intel_crtc *crtc)
bool intel_crtc_vrr_disabling(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);

View File

@ -532,6 +532,9 @@ void intel_plane_fixup_bitmasks(struct intel_crtc_state *crtc_state);
void intel_update_watermarks(struct drm_i915_private *i915);
bool intel_crtc_vrr_disabling(struct intel_atomic_state *state,
struct intel_crtc *crtc);
/* modesetting */
int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state,
const char *reason, u8 pipe_mask);

View File

@ -83,15 +83,72 @@ struct intel_dsb {
#define DSB_OPCODE_POLL 0xA
/* see DSB_REG_VALUE_MASK */
static int dsb_dewake_scanline(const struct intel_crtc_state *crtc_state)
static bool pre_commit_is_vrr_active(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
const struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
/* VRR will be enabled afterwards, if necessary */
if (intel_crtc_needs_modeset(new_crtc_state))
return false;
/* VRR will have been disabled during intel_pre_plane_update() */
return old_crtc_state->vrr.enable && !intel_crtc_vrr_disabling(state, crtc);
}
static const struct intel_crtc_state *
pre_commit_crtc_state(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
const struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
/*
* During fastsets/etc. the transcoder is still
* running with the old timings at this point.
*/
if (intel_crtc_needs_modeset(new_crtc_state))
return new_crtc_state;
else
return old_crtc_state;
}
static int dsb_vtotal(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
const struct intel_crtc_state *crtc_state = pre_commit_crtc_state(state, crtc);
if (pre_commit_is_vrr_active(state, crtc))
return crtc_state->vrr.vmax;
else
return intel_mode_vtotal(&crtc_state->hw.adjusted_mode);
}
static int dsb_dewake_scanline(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
const struct intel_crtc_state *crtc_state = pre_commit_crtc_state(state, crtc);
struct drm_i915_private *i915 = to_i915(state->base.dev);
unsigned int latency = skl_watermark_max_latency(i915, 0);
return intel_mode_vdisplay(&crtc_state->hw.adjusted_mode) -
intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, latency);
}
static int dsb_scanline_to_hw(struct intel_atomic_state *state,
struct intel_crtc *crtc, int scanline)
{
const struct intel_crtc_state *crtc_state = pre_commit_crtc_state(state, crtc);
int vtotal = dsb_vtotal(state, crtc);
return (scanline + vtotal - intel_crtc_scanline_offset(crtc_state)) % vtotal;
}
static u32 dsb_chicken(struct intel_crtc *crtc)
{
if (crtc->mode_flags & I915_MODE_FLAG_VRR)
@ -487,8 +544,6 @@ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state,
unsigned int max_cmds)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
intel_wakeref_t wakeref;
struct intel_dsb *dsb;
unsigned int size;
@ -524,7 +579,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state,
dsb->ins_start_offset = 0;
dsb->hw_dewake_scanline =
intel_crtc_scanline_to_hw(crtc_state, dsb_dewake_scanline(crtc_state));
dsb_scanline_to_hw(state, crtc, dsb_dewake_scanline(state, crtc));
return dsb;

View File

@ -190,7 +190,7 @@ static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
return scanline;
}
static int intel_crtc_scanline_offset(const struct intel_crtc_state *crtc_state)
int intel_crtc_scanline_offset(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
@ -284,14 +284,6 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
return (position + vtotal + crtc->scanline_offset) % vtotal;
}
int intel_crtc_scanline_to_hw(const struct intel_crtc_state *crtc_state,
int scanline)
{
int vtotal = intel_mode_vtotal(&crtc_state->hw.adjusted_mode);
return (scanline + vtotal - intel_crtc_scanline_offset(crtc_state)) % vtotal;
}
/*
* The uncore version of the spin lock functions is used to decide
* whether we need to lock the uncore lock or not. This is only

View File

@ -40,7 +40,6 @@ void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc);
void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc);
void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state,
bool vrr_enable);
int intel_crtc_scanline_to_hw(const struct intel_crtc_state *crtc_state,
int scanline);
int intel_crtc_scanline_offset(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_VBLANK_H__ */