[PATCH 41/44] drm/i915/hdmi_frl_dfm: Handle FRL Link M/N

Ankit Nautiyal <[email protected]>
Newsgroups org.freedesktop.lists.intel-xe,org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-gfx
Message-ID <[email protected]>
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.

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

Program the Link M/N after FRL link training and along with the DFM
registers, just before enabling the transcoder.

Read it back in the FRL readout for the state checker.

Bspec: 68848
Signed-off-by: Vandita Kulkarni <[email protected]>
Signed-off-by: Ankit Nautiyal <[email protected]>
---
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
index 36ac13b2539b..58fc55cb09e3 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
@@ -3,6 +3,7 @@
  * Copyright © 2022 Intel Corp
  */
 
+#include <linux/gcd.h>
 #include <linux/kernel.h>
 
 #include <drm/drm_connector.h>
@@ -709,6 +710,28 @@ bool intel_hdmi_frl_dfm_dsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm)
 	return true;
 }
 
+static void frl_set_m_n(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+	intel_de_write(display, PIPE_LINK_M1(display, cpu_transcoder),
+		       crtc_state->frl.link_m);
+	intel_de_write(display, PIPE_LINK_N1(display, cpu_transcoder),
+		       crtc_state->frl.link_n);
+}
+
+static void frl_get_m_n(struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+	crtc_state->frl.link_m = intel_de_read(display, PIPE_LINK_M1(display, cpu_transcoder)) &
+				 DATA_LINK_M_N_MASK;
+	crtc_state->frl.link_n = intel_de_read(display, PIPE_LINK_N1(display, cpu_transcoder)) &
+				 DATA_LINK_M_N_MASK;
+}
+
 void intel_hdmi_frl_dfm_write(const struct intel_crtc_state *crtc_state)
 {
 	struct intel_display *display = to_intel_display(crtc_state);
@@ -719,6 +742,8 @@ void intel_hdmi_frl_dfm_write(const struct intel_crtc_state *crtc_state)
 	if (!crtc_state->frl.enable)
 		return;
 
+	frl_set_m_n(crtc_state);
+
 	reg = TRANS_HDMI_FRL_DFMWRCTL(display, cpu_trans);
 	val = TB_ACTUAL_OFFSET(crtc_state->frl.tb_actual);
 	intel_de_rmw(display, reg, TB_ACTUAL_OFFSET_MASK, val);
@@ -737,6 +762,8 @@ void intel_hdmi_frl_dfm_read(struct intel_crtc_state *crtc_state)
 	if (!crtc_state->frl.enable)
 		return;
 
+	frl_get_m_n(crtc_state);
+
 	val = intel_de_read(display, TRANS_HDMI_FRL_DFMWRCTL(display, cpu_trans));
 	crtc_state->frl.tb_actual =
 		REG_FIELD_GET(TB_ACTUAL_OFFSET_MASK, val);
@@ -761,6 +788,38 @@ get_drm_color_format(enum intel_output_format output_format)
 	}
 }
 
+static void
+compute_frl_mn(struct intel_crtc_state *crtc_state, u32 ftb_avg_k)
+{
+	u64 ftb_avg, div_18_clk, gcd_val;
+	u32 link_m, link_n;
+
+	ftb_avg = 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 24-bit (DATA_LINK_M_N_MASK). 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 > DATA_LINK_M_N_MASK ||
+	       link_n > DATA_LINK_M_N_MASK) {
+		link_m >>= 1;
+		link_n >>= 1;
+	}
+
+	crtc_state->frl.link_m = link_m;
+	crtc_state->frl.link_n = link_n;
+
+	/* Frl div 18 stored in Khz */
+	crtc_state->frl.div18 = DIV_ROUND_UP_ULL(div_18_clk, 1000);
+}
+
 int intel_hdmi_frl_dfm_compute_config(struct intel_encoder *encoder,
 				      struct intel_crtc_state *crtc_state)
 {
@@ -824,5 +883,10 @@ int intel_hdmi_frl_dfm_compute_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);
+
 	return 0;
 }
-- 
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.