On 7/14/2026 4:09 PM, Mitul Golani wrote:
Add a per-CRTC debugfs file 'intel_vrr_cmrr' that lets the user force a
CMRR target refresh rate and video-mode requirement.
The file uses a "numerator/denominator" format:
- numerator: requested refresh rate in milli-Hz
(refresh rate in Hz * 1000, e.g. 60000 for 60 Hz)
- denominator: 1000 for a 1:1 ratio (no video timing) or
1001 for the 1000/1001 video timing
Reading the file reports the currently stored values; writing updates
them. The file is created only on platforms with VRR and CMRR support.
--v2:
- Drop the "vrr" debugfs subdirectory and expose a single flat,
intel_-prefixed "intel_vrr_cmrr" file (Jani, Nikula)
- Rename struct intel_crtc.cmrr to force_cmrr to make its purpose
explicit (Chaitanya)
- Fix parse comment: numerator unit is milli-Hz, not KHz (Chaitanya)
- Add debugfs/intel_ prefixes to the debugfs handler functions (Chaitanya)
- Expand commit message with debugfs entry semantics (Chaitanya)
Signed-off-by: Mitul Golani <[email protected]>
---
.../drm/i915/display/intel_display_debugfs.c | 2 +
.../drm/i915/display/intel_display_types.h | 5 +
drivers/gpu/drm/i915/display/intel_vrr.c | 103 ++++++++++++++++++
drivers/gpu/drm/i915/display/intel_vrr.h | 2 +
4 files changed, 112 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 3f02868ef105..2bbf4760dc30 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -49,6 +49,7 @@
#include "intel_psr.h"
#include "intel_psr_regs.h"
#include "intel_vdsc.h"
+#include "intel_vrr.h"
#include "intel_wm.h"
#include "intel_tc.h"
@@ -1395,6 +1396,7 @@ void intel_crtc_debugfs_add(struct intel_crtc *crtc)
intel_drrs_crtc_debugfs_add(crtc);
intel_fbc_crtc_debugfs_add(crtc);
hsw_ips_crtc_debugfs_add(crtc);
+ intel_vrr_crtc_debugfs_add(crtc);
debugfs_create_file("i915_current_bpc", 0444, root, crtc,
&i915_current_bpc_fops);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
b/drivers/gpu/drm/i915/display/intel_display_types.h
index c048da7d6fea..84a6d016e226 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1546,6 +1546,11 @@ struct intel_crtc {
u64 flip_count;
} dc_balance;
+ struct {
+ u32 numerator;
+ u32 denominator;
+ } force_cmrr;
+
int scanline_offset;
struct {
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c
b/drivers/gpu/drm/i915/display/intel_vrr.c
index 51e4f3309b8b..8b6e36ee9f55 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -4,6 +4,10 @@
*
*/
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
#include <drm/drm_print.h>
#include <drm/intel/step.h>
@@ -1231,3 +1235,102 @@ int intel_vrr_dcb_vmax_vblank_start_final(const struct intel_crtc_state *crtc_st
return intel_vrr_vblank_start(crtc_state, VRR_DCB_VMAX(tmp) + 1);
}
+
+static
+int intel_vrr_cmrr_parse_ratio(char *str, u32 *numerator, u32 *denominator)
+{
+ char *sep;
+ int ret;
+
+ /*
+ * Parse a "numerator/denominator" CMRR ratio string. The numerator
+ * is the requested refresh rate in milli-Hz (refresh rate in Hz * 1000)
+ * and the denominator selects the timing: 1000 for a 1:1 ratio
+ * (no video timing) or 1001 for the 1000/1001 video timing.
+ */
+
+ sep = strchr(str, '/');
+ if (!sep)
+ return -EINVAL;
+
+ *sep = '\0';
+
+ ret = kstrtou32(strim(str), 10, numerator);
+ if (ret)
+ return ret;
+
+ ret = kstrtou32(strim(sep + 1), 10, denominator);
+ if (ret)
+ return ret;
+
+ if (*numerator == 0)
+ return -EINVAL;
+
+ if (*denominator != 1000 && *denominator != 1001)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int intel_vrr_debugfs_cmrr_show(struct seq_file *m, void *data)
+{
+ struct intel_crtc *crtc = m->private;
+
+ seq_printf(m, "%u/%u\n", crtc->force_cmrr.numerator,
crtc->force_cmrr.denominator);
+
+ return 0;
+}
+
+static int intel_vrr_debugfs_cmrr_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intel_vrr_debugfs_cmrr_show, inode->i_private);
+}
+
+static ssize_t intel_vrr_debugfs_cmrr_write(struct file *file, const char
__user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct intel_crtc *crtc = m->private;
+ u32 numerator, denominator;
+ char kbuf[32];
+ int ret;
+
+ if (len >= sizeof(kbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, ubuf, len))
+ return -EFAULT;
+
+ kbuf[len] = '\0';
+
+ ret = intel_vrr_cmrr_parse_ratio(kbuf, &numerator, &denominator);
+ if (ret)
+ return ret;
+
+ crtc->force_cmrr.numerator = numerator;
+ crtc->force_cmrr.denominator = denominator;
+
+ return len;
+}
+
+static const struct file_operations intel_vrr_debugfs_cmrr_fops = {
+ .owner = THIS_MODULE,
+ .open = intel_vrr_debugfs_cmrr_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = intel_vrr_debugfs_cmrr_write,
+};
+
+void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc)
+{
+ struct intel_display *display = to_intel_display(crtc);
+
+ if (!HAS_VRR(display))
+ return;
+
+ if (HAS_CMRR(display))
+ debugfs_create_file("intel_vrr_cmrr", 0600,
crtc->base.debugfs_entry,
As discussed, please rename it to target_refresh_rate to cater to future
use of the debugfs for other features.
Ideally rest of the function names should be changed accordingly but
that can be handled later.
+ crtc, &intel_vrr_debugfs_cmrr_fops);
+}
+
trailing new line in EOF
With these fixed.
Reviewed-by: Chaitanya Kumar Borah <[email protected]>
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h
b/drivers/gpu/drm/i915/display/intel_vrr.h
index 55e9c429f579..19c7990be1b2 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.h
+++ b/drivers/gpu/drm/i915/display/intel_vrr.h
@@ -56,4 +56,6 @@ int intel_vrr_dcb_vmax_vblank_start_next(const struct
intel_crtc_state *crtc_sta
int intel_vrr_dcb_vmin_vblank_start_final(const struct intel_crtc_state
*crtc_state);
int intel_vrr_dcb_vmax_vblank_start_final(const struct intel_crtc_state
*crtc_state);
+void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc);
+
#endif /* __INTEL_VRR_H__ */