On 6/16/2026 8:12 PM, Mitul Golani wrote:
Add a per-CRTC debugfs entry 'vrr/cmrr' and a debugfs file
(numerator/denominator) that indicates user intended target
refresh rate and video mode requirement.
Please add more details regarding the semantics of the debugfs entry.
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 | 105 ++++++++++++++++++
drivers/gpu/drm/i915/display/intel_vrr.h | 2 +
4 files changed, 114 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 08004c1ba03f..1ce6e73ec83c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -48,6 +48,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"
@@ -1393,6 +1394,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 6cd102a3b610..897a1ffd7b79 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1545,6 +1545,11 @@ struct intel_crtc {
u64 flip_count;
} dc_balance;
+ struct {
+ u32 numerator;
+ u32 denominator;
+ } cmrr;
+
Please make it explicity that these are use to force CMRR refresh rates.
Something like *force_cmrr* would work better.
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 cd380fe8fd01..41118883b845 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 "intel_alpm.h"
@@ -1231,3 +1235,104 @@ 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 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 KHz
incorrect it is milli-Hz
For 60Hz, numerator will be 60000.
(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;
We could use some check for the numerator too. Perhaps some common
refresh rates or the ones that we expect IGTs to be written or valid
once from the edid. Check could be either here or in compute_config.
+
+ return 0;
+}
+
+static int intel_vrr_cmrr_show(struct seq_file *m, void *data)
+{
+ struct intel_crtc *crtc = m->private;
+
+ seq_printf(m, "%u/%u\n", crtc->cmrr.numerator, crtc->cmrr.denominator);
+
+ return 0;
+}
+
+static int intel_vrr_cmrr_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intel_vrr_cmrr_show, inode->i_private);
+}
+
+static ssize_t intel_vrr_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 = cmrr_parse_ratio(kbuf, &numerator, &denominator);
+ if (ret)
+ return ret;
+
+ crtc->cmrr.numerator = numerator;
+ crtc->cmrr.denominator = denominator;
+
+ return len;
+}
+
Please add *_debugfs_* to the function (that explicitly handles the
debugfs) that are missing it.
+static const struct file_operations intel_vrr_cmrr_fops = {
+ .owner = THIS_MODULE,
+ .open = intel_vrr_cmrr_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = intel_vrr_cmrr_write,
+};
+
+void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc)
+{
+ struct intel_display *display = to_intel_display(crtc);
+ struct dentry *vrr_dir;
+
+ if (!HAS_VRR(display))
+ return;
+
+ vrr_dir = debugfs_create_dir("vrr", crtc->base.debugfs_entry);
+
+ if (HAS_CMRR(display))
+ debugfs_create_file("cmrr", 0600, vrr_dir, crtc,
+ &intel_vrr_cmrr_fops);
+}
+
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__ */