summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_vrr.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2025-02-27 07:13:27 +1000
committerDave Airlie <airlied@redhat.com>2025-02-27 07:13:41 +1000
commit16893dd23f6d1e3a4dd6da272ef9960825da3ebd (patch)
tree716135b49731185618a75cc48b986fe4bc2d0c5a /drivers/gpu/drm/i915/display/intel_vrr.c
parent425b8481750abce45fa4aeecf6c32152cadbfa15 (diff)
parent5b99dd12fe53c745b40191b9e7fe9a25653b4e7a (diff)
Merge tag 'drm-intel-next-2025-02-24' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
drm/i915 feature pull for v6.15: Features and functionality: - Enable DP 128b/132b SST DSC (Jani, Imre) - Allow DSB to perform commits when VRR is enabled (Ville) - Compute HDMI PLLs for SNPS/C10 PHYs for rates not in fixed tables (Ankit) - Allow DSB usage when PSR is enabled on LNL+ (Jouni) - Enable Panel Replay mode change without full modeset (Jouni) - Enable async flips with compressed buffers on ICL+ (Ville) - Support luminance based brightness control via DPCD for eDP (Suraj) - Enable VRR enable/disable without full modeset (Mitul, Ankit) - Add debugfs facility for force testing HDCP 1.4 (Suraj) - Add scaler tracepoints, improve plane tracepoints (Ville) - Improve DMC wakelock debugging facilities (Gustavo) - Allow GuC SLPC default strategies on MTL+ for performance (Rodrigo) - Provide more information on display faults (Ville) Refactoring and cleanups: - Continue conversions to struct intel_display (Ville, Jani, Suraj, Imre) - Joiner and Y plane reorganization (Ville) - Move HDCP debugfs to intel_hdcp.c (Jani) - Clean up and unify LSPCON interfaces (Jani) - Move code out of intel_display.c to reduce its size (Ville) - Clean up and simplify DDI port enabling/disabling (Imre) - Make LPT LP a dedicated PCH type, refactor (Jani) - Simplify DSC range BPG offset calculation (Ankit) - Scaler cleanups (Ville) - Remove unused code from GVT (David Alan Gilbert) - Improve plane debugging (Ville) - DSB and VRR refactoring (Ville) Fixes: - Check if vblank is sufficient for DSC prefill and scaler (Mitul) - Fix Mesa clear color alignment regression (Ville) - Add missing TC DP PHY lane stagger delay (Imre) - Fix DSB + VRR usage for PTL+ (Ville) - Improve robustness of display VT-d workarounds (Ville) - Fix platforms for dbuf tracker state service programming (Ravi) - Fix DMC wakelock support conditions (Gustavo) - Amend DMC wakelock register ranges (Gustavo) - Disable the Common Primary Timing Generator (CMTG) (Gustavo) - Enable C20 PHY SSC (Suraj) - Add workaround for DKL PHY DP mode write (Nemesa) - Fix build warnings on clamp() usage (Guenter Roeck, Ankit) - Fix error handling while adding a connector (Imre) - Avoid full modeset at probe on vblank delay mismatches (Ville) - Fix encoder HDMI check for HDCP line rekeying (Suraj) - Fix HDCP repeater authentication during topology change (Suraj) - Handle display PHY power state reset for power savings (Mika) - Fix typos all over the place (Nitin) - Update HDMI TMDS C20 parameters for various platforms (Dnyaneshwar) - Guarantee a minimum hblank time for 128b/132b and 8b/10b MST (Arun, Imre) - Do not hardcode LSPCON settle timeout (Giedrius Statkevičius) Xe driver changes: - Re-use display vmas when possible (Maarten) - Remove double pageflip (Maarten) - Enable DP tunneling (Imre) - Separate i915 and xe tracepoints (Ville) DRM core changes: - Increase DPCD eDP display control CAP size to 5 bytes (Suraj) - Add DPCD eDP version 1.5 definition (Suraj) - Add timeout parameter to drm_lspcon_set_mode() (Giedrius Statkevičius) Merges: - Backmerge drm-next (Jani) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/87h64j7b7n.fsf@intel.com
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_vrr.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c170
1 files changed, 140 insertions, 30 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index 70088e355055..cac49319026d 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -7,9 +7,9 @@
#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
@@ -75,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
@@ -98,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
@@ -202,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
@@ -235,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);
@@ -255,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);
}
}
@@ -315,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;
@@ -325,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)
@@ -351,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 |
@@ -381,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)
@@ -424,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 =
@@ -439,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;
}