On 7/16/2026 8:07 PM, Naladala, Ramanaidu wrote:
Hi Mitul,

Resending this, as it was previously sent only to i915 by mistake.

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,
+                    crtc, &intel_vrr_debugfs_cmrr_fops);
+}

The debugfs interface accepts non-zero values, but fails to reset the value to zero.


Yeah I think we will also need some magic value to let the driver know to disable the feature. Since 0/0 is the default value shown by the debugfs entry that makes the most sense.

echo '0/0' > <file name>

to disable the CMRR. IGT can use it restore the state after testing is done.

+
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__ */

Reply via email to