diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_vrr.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_vrr.c | 173 |
1 files changed, 141 insertions, 32 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 19a5d0076bb8..cac49319026d 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -4,13 +4,12 @@ * */ -#include "i915_drv.h" #include "i915_reg.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_vrr.h" #include "intel_vrr_regs.h" -#include "intel_dp.h" #define FIXED_POINT_PRECISION 100 #define CMRR_PRECISION_TOLERANCE 10 @@ -76,6 +75,46 @@ intel_vrr_check_modeset(struct intel_atomic_state *state) } } +static int intel_vrr_real_vblank_delay(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->hw.adjusted_mode.crtc_vblank_start - + crtc_state->hw.adjusted_mode.crtc_vdisplay; +} + +static int intel_vrr_extra_vblank_delay(struct intel_display *display) +{ + /* + * On ICL/TGL VRR hardware inserts one extra scanline + * just after vactive, which pushes the vmin decision + * boundary ahead accordingly. We'll include the extra + * scanline in our vblank delay estimates to make sure + * that we never underestimate how long we have until + * the delayed vblank has passed. + */ + return DISPLAY_VER(display) < 13 ? 1 : 0; +} + +int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + return intel_vrr_real_vblank_delay(crtc_state) + + intel_vrr_extra_vblank_delay(display); +} + +static int intel_vrr_flipline_offset(struct intel_display *display) +{ + /* ICL/TGL hardware imposes flipline>=vmin+1 */ + return DISPLAY_VER(display) < 13 ? 1 : 0; +} + +static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + return crtc_state->vrr.vmin + intel_vrr_flipline_offset(display); +} + /* * Without VRR registers get latched at: * vblank_start @@ -99,19 +138,41 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat if (DISPLAY_VER(display) >= 13) return crtc_state->vrr.guardband; else - /* The hw imposes the extra scanline before frame start */ + /* hardware imposes one extra scanline somewhere */ return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1; } +int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + /* Min vblank actually determined by flipline */ + if (DISPLAY_VER(display) >= 13) + return intel_vrr_vmin_flipline(crtc_state); + else + return intel_vrr_vmin_flipline(crtc_state) + + intel_vrr_real_vblank_delay(crtc_state); +} + +int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (DISPLAY_VER(display) >= 13) + return crtc_state->vrr.vmax; + else + return crtc_state->vrr.vmax + + intel_vrr_real_vblank_delay(crtc_state); +} + int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state) { - /* Min vblank actually determined by flipline that is always >=vmin+1 */ - return crtc_state->vrr.vmin + 1 - intel_vrr_vblank_exit_length(crtc_state); + return intel_vrr_vmin_vtotal(crtc_state) - intel_vrr_vblank_exit_length(crtc_state); } int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state) { - return crtc_state->vrr.vmax - intel_vrr_vblank_exit_length(crtc_state); + return intel_vrr_vmax_vtotal(crtc_state) - intel_vrr_vblank_exit_length(crtc_state); } static bool @@ -203,15 +264,17 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, if (vmin >= vmax) return; + crtc_state->vrr.vmin = vmin; + crtc_state->vrr.vmax = vmax; + + crtc_state->vrr.flipline = crtc_state->vrr.vmin; + /* * flipline determines the min vblank length the hardware will - * generate, and flipline>=vmin+1, hence we reduce vmin by one - * to make sure we can get the actual min vblank length. + * generate, and on ICL/TGL flipline>=vmin+1, hence we reduce + * vmin by one to make sure we can get the actual min vblank length. */ - crtc_state->vrr.vmin = vmin - 1; - crtc_state->vrr.vmax = vmax; - - crtc_state->vrr.flipline = crtc_state->vrr.vmin + 1; + crtc_state->vrr.vmin -= intel_vrr_flipline_offset(display); /* * When panel is VRR capable and userspace has @@ -236,7 +299,7 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } - if (intel_dp->as_sdp_supported && crtc_state->vrr.enable) { + if (HAS_AS_SDP(display)) { crtc_state->vrr.vsync_start = (crtc_state->hw.adjusted_mode.crtc_vtotal - crtc_state->hw.adjusted_mode.vsync_start); @@ -256,11 +319,20 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) if (DISPLAY_VER(display) >= 13) { crtc_state->vrr.guardband = - crtc_state->vrr.vmin + 1 - adjusted_mode->crtc_vblank_start; + crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; } else { + /* hardware imposes one extra scanline somewhere */ crtc_state->vrr.pipeline_full = min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start - crtc_state->framestart_delay - 1); + + /* + * vmin/vmax/flipline also need to be adjusted by + * the vblank delay to maintain correct vtotals. + */ + crtc_state->vrr.vmin -= intel_vrr_real_vblank_delay(crtc_state); + crtc_state->vrr.vmax -= intel_vrr_real_vblank_delay(crtc_state); + crtc_state->vrr.flipline -= intel_vrr_real_vblank_delay(crtc_state); } } @@ -288,7 +360,7 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) * ADL/DG2: make TRANS_SET_CONTEXT_LATENCY effective with VRR */ if (IS_DISPLAY_VER(display, 12, 13)) - intel_de_rmw(display, CHICKEN_TRANS(cpu_transcoder), + intel_de_rmw(display, CHICKEN_TRANS(display, cpu_transcoder), 0, PIPE_VBLANK_WITH_DELAY); if (!intel_vrr_possible(crtc_state)) { @@ -316,9 +388,16 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) trans_vrr_ctl(crtc_state)); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), crtc_state->vrr.flipline - 1); + + if (HAS_AS_SDP(display)) + intel_de_write(display, + TRANS_VRR_VSYNC(display, cpu_transcoder), + VRR_VSYNC_END(crtc_state->vrr.vsync_end) | + VRR_VSYNC_START(crtc_state->vrr.vsync_start)); } -void intel_vrr_send_push(const struct intel_crtc_state *crtc_state) +void intel_vrr_send_push(struct intel_dsb *dsb, + const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; @@ -326,8 +405,49 @@ void intel_vrr_send_push(const struct intel_crtc_state *crtc_state) if (!crtc_state->vrr.enable) return; - intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), - TRANS_PUSH_EN | TRANS_PUSH_SEND); + if (dsb) + intel_dsb_nonpost_start(dsb); + + intel_de_write_dsb(display, dsb, + TRANS_PUSH(display, cpu_transcoder), + TRANS_PUSH_EN | TRANS_PUSH_SEND); + + if (dsb) + intel_dsb_nonpost_end(dsb); +} + +void intel_vrr_check_push_sent(struct intel_dsb *dsb, + const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + + if (!crtc_state->vrr.enable) + return; + + /* + * Make sure the push send bit has cleared. This should + * already be the case as long as the caller makes sure + * this is called after the delayed vblank has occurred. + */ + if (dsb) { + int wait_us, count; + + wait_us = 2; + count = 1; + + /* + * If the bit hasn't cleared the DSB will + * raise the poll error interrupt. + */ + intel_dsb_poll(dsb, TRANS_PUSH(display, cpu_transcoder), + TRANS_PUSH_SEND, 0, wait_us, count); + } else { + if (intel_vrr_is_push_sent(crtc_state)) + drm_err(display->drm, "[CRTC:%d:%s] VRR push send still pending\n", + crtc->base.base.id, crtc->base.name); + } } bool intel_vrr_is_push_sent(const struct intel_crtc_state *crtc_state) @@ -352,12 +472,6 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state) intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), TRANS_PUSH_EN); - if (HAS_AS_SDP(display)) - intel_de_write(display, - TRANS_VRR_VSYNC(display, cpu_transcoder), - VRR_VSYNC_END(crtc_state->vrr.vsync_end) | - VRR_VSYNC_START(crtc_state->vrr.vsync_start)); - if (crtc_state->cmrr.enable) { intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), VRR_CTL_VRR_ENABLE | VRR_CTL_CMRR_ENABLE | @@ -382,10 +496,6 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) TRANS_VRR_STATUS(display, cpu_transcoder), VRR_STATUS_VRR_EN_LIVE, 1000); intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); - - if (HAS_AS_SDP(display)) - intel_de_write(display, - TRANS_VRR_VSYNC(display, cpu_transcoder), 0); } void intel_vrr_get_config(struct intel_crtc_state *crtc_state) @@ -425,10 +535,6 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) TRANS_VRR_VMAX(display, cpu_transcoder)) + 1; crtc_state->vrr.vmin = intel_de_read(display, TRANS_VRR_VMIN(display, cpu_transcoder)) + 1; - } - - if (crtc_state->vrr.enable) { - crtc_state->mode_flags |= I915_MODE_FLAG_VRR; if (HAS_AS_SDP(display)) { trans_vrr_vsync = @@ -440,4 +546,7 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) REG_FIELD_GET(VRR_VSYNC_END_MASK, trans_vrr_vsync); } } + + if (crtc_state->vrr.enable) + crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } |