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);
+}
+
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__ */
-- 
2.48.1

Reply via email to