drm/i915/vrr: Add per-CRTC vrr/cmrr debugfs control

Add a per-CRTC debugfs file 'intel_vrr_target_refresh_rate' 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)

--v3:
- Rename debugfs function and file name (Chaitanya)
- Remove railing new line at EOF (Chaitanya)
- Update CMRR guard conditions (Chaitanya)
- Add 0/0 default case. (Ramanaidu)

--v4:
- Correct CMRR guard check while creating debugfs

--v5:
- Commit message update (Chaitanya)
- Add support for 0/0 writing (Validation)

Signed-off-by: Mitul Golani <mitulkumar.ajitkumar.golani@intel.com>
Reviewed-by: Chaitanya Kumar Borah <chaitanya.kumar.borah@intel.com>
Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
Link: https://patch.msgid.link/20260730105919.3913412-4-mitulkumar.ajitkumar.golani@intel.com
This commit is contained in:
Mitul Golani 2026-07-30 16:29:10 +05:30 committed by Suraj Kandpal
parent dfd1495664
commit 9edafeb040
4 changed files with 121 additions and 0 deletions

View File

@ -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);

View File

@ -1553,6 +1553,11 @@ struct intel_crtc {
u64 flip_count;
} dc_balance;
struct {
u32 numerator;
u32 denominator;
} force_cmrr;
int scanline_offset;
struct {

View File

@ -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>
@ -1237,3 +1241,111 @@ 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;
/*
* "0/0" clears any previously configured CMRR override.
* A zero numerator already means "CMRR not requested" in
* intel_vrr_cmrr_compute_config(), so just let it through.
*/
if (*numerator == 0 && *denominator == 0)
return 0;
if (*numerator == 0)
return -EINVAL;
if (*denominator != 1000 && *denominator != 1001)
return -EINVAL;
return 0;
}
static int intel_vrr_debugfs_target_rr_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_target_rr_open(struct inode *inode, struct file *file)
{
return single_open(file, intel_vrr_debugfs_target_rr_show, inode->i_private);
}
static ssize_t intel_vrr_debugfs_target_rr_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;
if (crtc->force_cmrr.numerator == numerator &&
crtc->force_cmrr.denominator == denominator)
return len;
crtc->force_cmrr.numerator = numerator;
crtc->force_cmrr.denominator = denominator;
return len;
}
static const struct file_operations intel_vrr_debugfs_target_rr_fops = {
.owner = THIS_MODULE,
.open = intel_vrr_debugfs_target_rr_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = intel_vrr_debugfs_target_rr_write,
};
void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc)
{
struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
if (!intel_vrr_cmrr_possible(crtc_state))
return;
debugfs_create_file("intel_vrr_target_refresh_rate", 0600, crtc->base.debugfs_entry,
crtc, &intel_vrr_debugfs_target_rr_fops);
}

View File

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