diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_vrr.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_vrr.c | 498 |
1 files changed, 312 insertions, 186 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 3eed37f271b0..b92c42fde937 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -10,8 +10,11 @@ #include "intel_display_regs.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_psr.h" #include "intel_vrr.h" #include "intel_vrr_regs.h" +#include "skl_prefill.h" +#include "skl_watermark.h" #define FIXED_POINT_PRECISION 100 #define CMRR_PRECISION_TOLERANCE 10 @@ -22,6 +25,9 @@ bool intel_vrr_is_capable(struct intel_connector *connector) const struct drm_display_info *info = &connector->base.display_info; struct intel_dp *intel_dp; + if (!HAS_VRR(display)) + return false; + /* * DP Sink is capable of VRR video timings if * Ignore MSA bit is set in DPCD. @@ -46,8 +52,7 @@ bool intel_vrr_is_capable(struct intel_connector *connector) return false; } - return HAS_VRR(display) && - info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10; + return info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10; } bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh) @@ -79,44 +84,42 @@ 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. + * boundary ahead accordingly, and thus reduces the + * max guardband length by one scanline. */ return DISPLAY_VER(display) < 13 ? 1 : 0; } -int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) +static int intel_vrr_vmin_flipline_offset(struct intel_display *display) { - struct intel_display *display = to_intel_display(crtc_state); - - return intel_vrr_real_vblank_delay(crtc_state) + - intel_vrr_extra_vblank_delay(display); + /* + * ICL/TGL hardware imposes flipline>=vmin+1 + * + * We reduce the vmin value to compensate when programming the + * hardware. This approach allows flipline to remain set at the + * original value, and thus the frame will have the desired + * minimum vtotal. + */ + return DISPLAY_VER(display) < 13 ? 1 : 0; } -static int intel_vrr_flipline_offset(struct intel_display *display) +static int intel_vrr_guardband_to_pipeline_full(const struct intel_crtc_state *crtc_state, + int guardband) { - /* ICL/TGL hardware imposes flipline>=vmin+1 */ - return DISPLAY_VER(display) < 13 ? 1 : 0; + /* hardware imposes one extra scanline somewhere */ + return guardband - crtc_state->framestart_delay - 1; } -static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) +static int intel_vrr_pipeline_full_to_guardband(const struct intel_crtc_state *crtc_state, + int pipeline_full) { - struct intel_display *display = to_intel_display(crtc_state); - - return crtc_state->vrr.vmin + intel_vrr_flipline_offset(display); + /* hardware imposes one extra scanline somewhere */ + return pipeline_full + crtc_state->framestart_delay + 1; } /* @@ -135,48 +138,26 @@ static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) * * framestart_delay is programmable 1-4. */ -static int intel_vrr_vblank_exit_length(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.guardband; - else - /* 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); + return crtc_state->vrr.vmin; } 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); + return crtc_state->vrr.vmax; } int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state) { - return intel_vrr_vmin_vtotal(crtc_state) - intel_vrr_vblank_exit_length(crtc_state); + return intel_vrr_vmin_vtotal(crtc_state) - crtc_state->vrr.guardband; } int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state) { - return intel_vrr_vmax_vtotal(crtc_state) - intel_vrr_vblank_exit_length(crtc_state); + return intel_vrr_vmax_vtotal(crtc_state) - crtc_state->vrr.guardband; } static bool @@ -230,7 +211,6 @@ cmrr_get_vtotal(struct intel_crtc_state *crtc_state, bool video_mode_required) static void intel_vrr_compute_cmrr_timings(struct intel_crtc_state *crtc_state) { - crtc_state->cmrr.enable = true; /* * TODO: Compute precise target refresh rate to determine * if video_mode_required should be true. Currently set to @@ -240,52 +220,76 @@ void intel_vrr_compute_cmrr_timings(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmax = cmrr_get_vtotal(crtc_state, false); crtc_state->vrr.vmin = crtc_state->vrr.vmax; crtc_state->vrr.flipline = crtc_state->vrr.vmin; + + crtc_state->cmrr.enable = true; crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } static -void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state) +void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state, + int vmin, int vmax) { + crtc_state->vrr.vmax = vmax; + crtc_state->vrr.vmin = vmin; + crtc_state->vrr.flipline = crtc_state->vrr.vmin; + crtc_state->vrr.enable = true; crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } -/* - * For fixed refresh rate mode Vmin, Vmax and Flipline all are set to - * Vtotal value. - */ static -int intel_vrr_fixed_rr_vtotal(const struct intel_crtc_state *crtc_state) +void intel_vrr_compute_fixed_rr_timings(struct intel_crtc_state *crtc_state) +{ + /* For fixed rr, vmin = vmax = flipline */ + crtc_state->vrr.vmax = crtc_state->hw.adjusted_mode.crtc_vtotal; + crtc_state->vrr.vmin = crtc_state->vrr.vmax; + crtc_state->vrr.flipline = crtc_state->vrr.vmin; +} + +static int intel_vrr_hw_value(const struct intel_crtc_state *crtc_state, + int value) { struct intel_display *display = to_intel_display(crtc_state); - int crtc_vtotal = crtc_state->hw.adjusted_mode.crtc_vtotal; + /* + * On TGL vmin/vmax/flipline also need to be + * adjusted by the SCL to maintain correct vtotals. + */ if (DISPLAY_VER(display) >= 13) - return crtc_vtotal; + return value; else - return crtc_vtotal - - intel_vrr_real_vblank_delay(crtc_state); + return value - crtc_state->set_context_latency; +} + +/* + * For fixed refresh rate mode Vmin, Vmax and Flipline all are set to + * Vtotal value. + */ +static +int intel_vrr_fixed_rr_hw_vtotal(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->hw.adjusted_mode.crtc_vtotal); } static -int intel_vrr_fixed_rr_vmax(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmax(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } static -int intel_vrr_fixed_rr_vmin(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmin(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - return intel_vrr_fixed_rr_vtotal(crtc_state) - - intel_vrr_flipline_offset(display); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state) - + intel_vrr_vmin_flipline_offset(display); } static -int intel_vrr_fixed_rr_flipline(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_flipline(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) @@ -297,22 +301,11 @@ void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) return; intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - intel_vrr_fixed_rr_vmin(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - intel_vrr_fixed_rr_vmax(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - intel_vrr_fixed_rr_flipline(crtc_state) - 1); -} - -static -void intel_vrr_compute_fixed_rr_timings(struct intel_crtc_state *crtc_state) -{ - /* - * For fixed rr, vmin = vmax = flipline. - * vmin is already set to crtc_vtotal set vmax and flipline the same. - */ - crtc_state->vrr.vmax = crtc_state->hw.adjusted_mode.crtc_vtotal; - crtc_state->vrr.flipline = crtc_state->hw.adjusted_mode.crtc_vtotal; + intel_vrr_fixed_rr_hw_flipline(crtc_state) - 1); } static @@ -384,60 +377,131 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, vmax = vmin; } - crtc_state->vrr.vmin = vmin; - crtc_state->vrr.vmax = vmax; - - crtc_state->vrr.flipline = crtc_state->vrr.vmin; - if (crtc_state->uapi.vrr_enabled && vmin < vmax) - intel_vrr_compute_vrr_timings(crtc_state); + intel_vrr_compute_vrr_timings(crtc_state, vmin, vmax); else if (is_cmrr_frac_required(crtc_state) && is_edp) intel_vrr_compute_cmrr_timings(crtc_state); else intel_vrr_compute_fixed_rr_timings(crtc_state); - /* - * flipline determines the min vblank length the hardware will - * 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 -= intel_vrr_flipline_offset(display); - if (HAS_AS_SDP(display)) { crtc_state->vrr.vsync_start = (crtc_state->hw.adjusted_mode.crtc_vtotal - - crtc_state->hw.adjusted_mode.vsync_start); + crtc_state->hw.adjusted_mode.crtc_vsync_start); crtc_state->vrr.vsync_end = (crtc_state->hw.adjusted_mode.crtc_vtotal - - crtc_state->hw.adjusted_mode.vsync_end); + crtc_state->hw.adjusted_mode.crtc_vsync_end); } } -void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) +static int +intel_vrr_max_hw_guardband(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + int max_pipeline_full = REG_FIELD_MAX(VRR_CTL_PIPELINE_FULL_MASK); + + if (DISPLAY_VER(display) >= 13) + return REG_FIELD_MAX(XELPD_VRR_CTL_VRR_GUARDBAND_MASK); + else + return intel_vrr_pipeline_full_to_guardband(crtc_state, + max_pipeline_full); +} + +static int +intel_vrr_max_vblank_guardband(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + return crtc_state->vrr.vmin - + adjusted_mode->crtc_vdisplay - + crtc_state->set_context_latency - + intel_vrr_extra_vblank_delay(display); +} + +static int +intel_vrr_max_guardband(struct intel_crtc_state *crtc_state) +{ + return min(intel_vrr_max_hw_guardband(crtc_state), + intel_vrr_max_vblank_guardband(crtc_state)); +} + +static +int intel_vrr_compute_optimized_guardband(struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct skl_prefill_ctx prefill_ctx; + int prefill_latency_us; + int guardband = 0; + + skl_prefill_init_worst(&prefill_ctx, crtc_state); + + /* + * The SoC power controller runs SAGV mutually exclusive with package C states, + * so the max of package C and SAGV latencies is used to compute the min prefill guardband. + * PM delay = max(sagv_latency, pkgc_max_latency (highest enabled wm level 1 and up)) + */ + prefill_latency_us = max(display->sagv.block_time_us, + skl_watermark_max_latency(display, 1)); + + guardband = skl_prefill_min_guardband(&prefill_ctx, + crtc_state, + prefill_latency_us); + + if (intel_crtc_has_dp_encoder(crtc_state)) { + guardband = max(guardband, intel_psr_min_guardband(crtc_state)); + guardband = max(guardband, intel_dp_sdp_min_guardband(crtc_state, true)); + } + + return guardband; +} + +static bool intel_vrr_use_optimized_guardband(const struct intel_crtc_state *crtc_state) +{ + /* + * #TODO: Enable optimized guardband for HDMI + * For HDMI lot of infoframes are transmitted a line or two after vsync. + * Since with optimized guardband the double bufferring point is at delayed vblank, + * we need to ensure that vsync happens after delayed vblank for the HDMI case. + */ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return false; + + return true; +} + +void intel_vrr_compute_guardband(struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + int guardband; + if (!intel_vrr_possible(crtc_state)) return; - if (DISPLAY_VER(display) >= 13) { - crtc_state->vrr.guardband = - 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); + if (intel_vrr_use_optimized_guardband(crtc_state)) + guardband = intel_vrr_compute_optimized_guardband(crtc_state); + else + guardband = crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay; + + crtc_state->vrr.guardband = min(guardband, intel_vrr_max_guardband(crtc_state)); + if (intel_vrr_always_use_vrr_tg(display)) { + adjusted_mode->crtc_vblank_start = + adjusted_mode->crtc_vtotal - crtc_state->vrr.guardband; /* - * vmin/vmax/flipline also need to be adjusted by - * the vblank delay to maintain correct vtotals. + * pipe_mode has already been derived from the + * original adjusted_mode, keep the two in sync. */ - 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); + pipe_mode->crtc_vblank_start = + adjusted_mode->crtc_vblank_start; } + + if (DISPLAY_VER(display) < 13) + crtc_state->vrr.pipeline_full = + intel_vrr_guardband_to_pipeline_full(crtc_state, + crtc_state->vrr.guardband); } static u32 trans_vrr_ctl(const struct intel_crtc_state *crtc_state) @@ -461,6 +525,9 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) struct intel_display *display = to_intel_display(crtc_state); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + if (!HAS_VRR(display)) + return; + /* * This bit seems to have two meanings depending on the platform: * TGL: generate VRR "safe window" for DSB vblank waits @@ -489,7 +556,7 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) intel_vrr_set_fixed_rr_timings(crtc_state); - if (!intel_vrr_always_use_vrr_tg(display) && !crtc_state->vrr.enable) + if (!intel_vrr_always_use_vrr_tg(display)) intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), trans_vrr_ctl(crtc_state)); @@ -498,6 +565,18 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) TRANS_VRR_VSYNC(display, cpu_transcoder), VRR_VSYNC_END(crtc_state->vrr.vsync_end) | VRR_VSYNC_START(crtc_state->vrr.vsync_start)); + + /* + * For BMG and LNL+ onwards the EMP_AS_SDP_TL is used for programming + * double buffering point and transmission line for VRR packets for + * HDMI2.1/DP/eDP/DP->HDMI2.1 PCON. + * Since currently we support VRR only for DP/eDP, so this is programmed + * to for Adaptive Sync SDP to Vsync start. + */ + if (DISPLAY_VERx100(display) == 1401 || DISPLAY_VER(display) >= 20) + intel_de_write(display, + EMP_AS_SDP_TL(display, cpu_transcoder), + EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start)); } void intel_vrr_send_push(struct intel_dsb *dsb, @@ -576,126 +655,128 @@ bool intel_vrr_always_use_vrr_tg(struct intel_display *display) return false; } -static -void intel_vrr_set_db_point_and_transmission_line(const struct intel_crtc_state *crtc_state) +static int intel_vrr_hw_vmin(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - /* - * For BMG and LNL+ onwards the EMP_AS_SDP_TL is used for programming - * double buffering point and transmission line for VRR packets for - * HDMI2.1/DP/eDP/DP->HDMI2.1 PCON. - * Since currently we support VRR only for DP/eDP, so this is programmed - * to for Adaptive Sync SDP to Vsync start. - */ - if (DISPLAY_VERx100(display) == 1401 || DISPLAY_VER(display) >= 20) - intel_de_write(display, - EMP_AS_SDP_TL(display, cpu_transcoder), - EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start)); + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin) - + intel_vrr_vmin_flipline_offset(display); } -void intel_vrr_enable(const struct intel_crtc_state *crtc_state) +static int intel_vrr_hw_vmax(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmax); +} + +static int intel_vrr_hw_flipline(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.flipline); +} + +static void intel_vrr_set_vrr_timings(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - if (!crtc_state->vrr.enable) - return; - intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - crtc_state->vrr.vmin - 1); + intel_vrr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - crtc_state->vrr.vmax - 1); + intel_vrr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - crtc_state->vrr.flipline - 1); + intel_vrr_hw_flipline(crtc_state) - 1); +} - intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), - TRANS_PUSH_EN); +static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state, + bool cmrr_enable) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 vrr_ctl; - if (!intel_vrr_always_use_vrr_tg(display)) { - intel_vrr_set_db_point_and_transmission_line(crtc_state); + intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), TRANS_PUSH_EN); - if (crtc_state->cmrr.enable) { - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), - VRR_CTL_VRR_ENABLE | VRR_CTL_CMRR_ENABLE | - trans_vrr_ctl(crtc_state)); - } else { - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), - VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state)); - } - } + vrr_ctl = VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state); + + /* + * FIXME this might be broken as bspec seems to imply that + * even VRR_CTL_CMRR_ENABLE is armed by TRANS_CMRR_N_HI + * when enabling CMRR (but not when disabling CMRR?). + */ + if (cmrr_enable) + vrr_ctl |= VRR_CTL_CMRR_ENABLE; + + intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), vrr_ctl); } -void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) +static void intel_vrr_tg_disable(const struct intel_crtc_state *old_crtc_state) { struct intel_display *display = to_intel_display(old_crtc_state); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; - if (!old_crtc_state->vrr.enable) - return; + intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), + trans_vrr_ctl(old_crtc_state)); - if (!intel_vrr_always_use_vrr_tg(display)) { - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), - trans_vrr_ctl(old_crtc_state)); - intel_de_wait_for_clear(display, - TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); - intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); - } + if (intel_de_wait_for_clear_ms(display, + TRANS_VRR_STATUS(display, cpu_transcoder), + VRR_STATUS_VRR_EN_LIVE, 1000)) + drm_err(display->drm, "Timed out waiting for VRR live status to clear\n"); - intel_vrr_set_fixed_rr_timings(old_crtc_state); + intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); } -void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state) +void intel_vrr_enable(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - if (!HAS_VRR(display)) + if (!crtc_state->vrr.enable) return; - if (!intel_vrr_possible(crtc_state)) - return; + intel_vrr_set_vrr_timings(crtc_state); - if (!intel_vrr_always_use_vrr_tg(display)) { - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), - trans_vrr_ctl(crtc_state)); - return; - } + if (!intel_vrr_always_use_vrr_tg(display)) + intel_vrr_tg_enable(crtc_state, crtc_state->cmrr.enable); +} - intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), - TRANS_PUSH_EN); +void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) +{ + struct intel_display *display = to_intel_display(old_crtc_state); - intel_vrr_set_db_point_and_transmission_line(crtc_state); + if (!old_crtc_state->vrr.enable) + return; - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), - VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state)); + if (!intel_vrr_always_use_vrr_tg(display)) + intel_vrr_tg_disable(old_crtc_state); + + intel_vrr_set_fixed_rr_timings(old_crtc_state); } -void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state) +void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - - if (!HAS_VRR(display)) - return; if (!intel_vrr_possible(crtc_state)) return; - intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), 0); + if (intel_vrr_always_use_vrr_tg(display)) + intel_vrr_tg_enable(crtc_state, false); +} - intel_de_wait_for_clear(display, TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); - intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); +void intel_vrr_transcoder_disable(const struct intel_crtc_state *old_crtc_state) +{ + struct intel_display *display = to_intel_display(old_crtc_state); + + if (!intel_vrr_possible(old_crtc_state)) + return; + + if (intel_vrr_always_use_vrr_tg(display)) + intel_vrr_tg_disable(old_crtc_state); } bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state) { return crtc_state->vrr.flipline && crtc_state->vrr.flipline == crtc_state->vrr.vmax && - crtc_state->vrr.flipline == intel_vrr_vmin_flipline(crtc_state); + crtc_state->vrr.flipline == crtc_state->vrr.vmin; } void intel_vrr_get_config(struct intel_crtc_state *crtc_state) @@ -720,14 +801,20 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) TRANS_CMRR_M_HI(display, cpu_transcoder)); } - if (DISPLAY_VER(display) >= 13) + if (DISPLAY_VER(display) >= 13) { crtc_state->vrr.guardband = REG_FIELD_GET(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, trans_vrr_ctl); - else - if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) + } else { + if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) { crtc_state->vrr.pipeline_full = REG_FIELD_GET(VRR_CTL_PIPELINE_FULL_MASK, trans_vrr_ctl); + crtc_state->vrr.guardband = + intel_vrr_pipeline_full_to_guardband(crtc_state, + crtc_state->vrr.pipeline_full); + } + } + if (trans_vrr_ctl & VRR_CTL_FLIP_LINE_EN) { crtc_state->vrr.flipline = intel_de_read(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder)) + 1; @@ -736,6 +823,15 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmin = intel_de_read(display, TRANS_VRR_VMIN(display, cpu_transcoder)) + 1; + if (DISPLAY_VER(display) < 13) { + /* undo what intel_vrr_hw_value() does when writing the values */ + crtc_state->vrr.flipline += crtc_state->set_context_latency; + crtc_state->vrr.vmax += crtc_state->set_context_latency; + crtc_state->vrr.vmin += crtc_state->set_context_latency; + + crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display); + } + /* * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal * bits are not filled. Since for these platforms TRAN_VMIN is always @@ -771,4 +867,34 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) */ if (crtc_state->vrr.enable) crtc_state->mode_flags |= I915_MODE_FLAG_VRR; + + /* + * For platforms that always use the VRR timing generator, we overwrite + * crtc_vblank_start with vtotal - guardband to reflect the delayed + * vblank start. This works for both default and optimized guardband values. + * On other platforms, we keep the original value from + * intel_get_transcoder_timings() and apply adjustments only in VRR-specific + * paths as needed. + */ + if (intel_vrr_always_use_vrr_tg(display)) + crtc_state->hw.adjusted_mode.crtc_vblank_start = + crtc_state->hw.adjusted_mode.crtc_vtotal - + crtc_state->vrr.guardband; +} + +int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (DISPLAY_VER(display) >= 30) + return crtc_state->hw.adjusted_mode.crtc_vdisplay - + crtc_state->set_context_latency; + else + return crtc_state->hw.adjusted_mode.crtc_vdisplay; +} + +int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_vmin_vblank_start(crtc_state) - + crtc_state->set_context_latency; } |
