From: Vandita Kulkarni <[email protected]>

For HDMI FRL, the transcoder Link M/N carries the ratio of the average
tribyte rate (ftb_avg) to the FRL div18 clock, unlike the pixel/link
clock ratio used for DP.

Compute link_m/link_n from ftb_avg and the required FRL rate, reduced by
their gcd. As PIPE_LINK_M1/N1 are 32-bit wide, scale both down preserving
the ratio until they fit, and store them in crtc_state.

v2: Use full 32 bits for LINK_M/N for HDMI2.1.

Bspec: 68848
Signed-off-by: Vandita Kulkarni <[email protected]>
Signed-off-by: Ankit Nautiyal <[email protected]>
---
 .../gpu/drm/i915/display/intel_display_regs.h |  1 +
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 38 +++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h 
b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 1abd221f966b..7e1c12560a00 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -863,6 +863,7 @@
 #define  TU_SIZE(x)            REG_FIELD_PREP(TU_SIZE_MASK, (x) - 1) /* 
default size 64 */
 #define  DATA_LINK_M_N_MASK    REG_GENMASK(23, 0)
 #define  DATA_LINK_N_MAX       (0x800000)
+#define  HDMI_FRL_LINK_M_N_MAX REG_GENMASK(31, 0)
 
 #define _PIPEA_DATA_N_G4X      0x70054
 #define _PIPEB_DATA_N_G4X      0x71054
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c 
b/drivers/gpu/drm/i915/display/intel_hdmi.c
index c5f25d2d6331..ce6ad9e28bee 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -27,6 +27,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/gcd.h>
 #include <linux/hdmi.h>
 #include <linux/i2c.h>
 #include <linux/iopoll.h>
@@ -2308,6 +2309,38 @@ static int intel_hdmi_compute_tmds_clock(struct 
intel_encoder *encoder,
        return 0;
 }
 
+static void
+compute_frl_mn(struct intel_crtc_state *crtc_state, u32 ftb_avg_k)
+{
+       u64 ftb_avg, div_18_clk, gcd_val;
+       u64 link_m, link_n;
+
+       ftb_avg = (u64)ftb_avg_k * 1000;
+       div_18_clk = mult_frac(1000000000, crtc_state->frl.required_rate, 18);
+       gcd_val = gcd(ftb_avg, div_18_clk);
+
+       link_m = DIV_ROUND_UP_ULL(ftb_avg, gcd_val);
+       link_n = DIV_ROUND_UP_ULL(div_18_clk, gcd_val);
+
+       /*
+        * PIPE_LINK_M1/N1 are 32-bit for HDMI2.1. Scale both
+        * down preserving the ratio until they fit the register width.
+        *
+        * #TODO check if intel_reduce_m_n_ratio() can be exported.
+        */
+       while (link_m > HDMI_FRL_LINK_M_N_MAX ||
+              link_n > HDMI_FRL_LINK_M_N_MAX) {
+               link_m >>= 1;
+               link_n >>= 1;
+       }
+
+       crtc_state->frl.link_m = (u32)link_m;
+       crtc_state->frl.link_n = (u32)link_n;
+
+       /* Frl div 18 stored in Khz */
+       crtc_state->frl.div18 = DIV_ROUND_UP_ULL(div_18_clk, 1000);
+}
+
 static int
 intel_hdmi_compute_frl_config(struct intel_encoder *encoder,
                              struct intel_crtc_state *crtc_state)
@@ -2378,6 +2411,11 @@ intel_hdmi_compute_frl_config(struct intel_encoder 
*encoder,
        else
                crtc_state->frl.tb_threshold_min = 492;
 
+       compute_frl_mn(crtc_state, frl_dfm.params.ftb_avg_k);
+       drm_dbg_kms(display->drm, "FRL Clock: link_m = %dHz, link_n = %dHz, 
div18 = %dKHz\n",
+                   crtc_state->frl.link_m, crtc_state->frl.link_n,
+                   crtc_state->frl.div18);
+
        /*
         * TODO
         * 1. Calculate condition for Reseource based scheduling enable.
-- 
2.50.1

Reply via email to