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 b7cc361fd955..46dd980b315a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1553,6 +1553,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 b0c9101e6ed3..615c8fa8c063 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -4,6 +4,10 @@ * */ +#include +#include +#include + #include #include @@ -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); +} 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__ */