[PATCH 36/44] drm/i915/hdmi_frl_dfm: Add function to compute FRL DFM config

Ankit Nautiyal <[email protected]>
Newsgroups org.freedesktop.lists.intel-xe,org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-gfx
Message-ID <[email protected]>
Add intel_hdmi_frl_dfm_compute_config() to find the lowest FRL rate
that meets the DFM requirements for a mode, and fill the crtc_state
with the computed DFM parameters and Link M/N.

Signed-off-by: Ankit Nautiyal <[email protected]>
Signed-off-by: Vandita Kulkarni <[email protected]>
---
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 82 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h |  3 +
 2 files changed, 85 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 51a09c05bef3..36ac13b2539b 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 
 #include <drm/drm_connector.h>
+#include <drm/drm_print.h>
 
 #include "intel_de.h"
 #include "intel_display_driver.h"
@@ -744,3 +745,84 @@ void intel_hdmi_frl_dfm_read(struct intel_crtc_state *crtc_state)
 	crtc_state->frl.tb_threshold_min =
 		REG_FIELD_GET(TB_MIN_THESHOLD_MASK, val);
 }
+
+static u32
+get_drm_color_format(enum intel_output_format output_format)
+{
+	switch (output_format) {
+	case INTEL_OUTPUT_FORMAT_RGB:
+		return DRM_OUTPUT_COLOR_FORMAT_RGB444;
+	case INTEL_OUTPUT_FORMAT_YCBCR420:
+		return DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+	case INTEL_OUTPUT_FORMAT_YCBCR444:
+		return DRM_OUTPUT_COLOR_FORMAT_YCBCR444;
+	default:
+		return DRM_OUTPUT_COLOR_FORMAT_RGB444;
+	}
+}
+
+int intel_hdmi_frl_dfm_compute_config(struct intel_encoder *encoder,
+				      struct intel_crtc_state *crtc_state)
+{
+	static const int rate[] = {9, 18, 24, 32, 40, 48};
+	static const int audio_freq_hz[] = {192000, 176400, 96000, 88200, 48000};
+	struct intel_hdmi_frl_dfm frl_dfm = {0};
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_display *display = to_intel_display(crtc_state);
+	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+	int max_rate = intel_hdmi->max_frl_rate;
+	bool can_support_frl_mode = false;
+	int i, j;
+
+	/* Fill mode related input params */
+	frl_dfm.config.pixel_clock_nominal_khz = adjusted_mode->clock;
+	frl_dfm.config.hactive = adjusted_mode->hdisplay;
+	frl_dfm.config.hblank = adjusted_mode->htotal - adjusted_mode->hdisplay;
+
+	/* Fill color related input params */
+	frl_dfm.config.bpc = crtc_state->pipe_bpp / 3;
+	frl_dfm.config.color_format = get_drm_color_format(crtc_state->output_format);
+
+	/*
+	 * Check if the resolution can be supported in FRL mode.
+	 * We try with the lowest FRL rate first — the minimum rate that
+	 * satisfies DFM requirements — for better SI margin and lower power.
+	 */
+	for (i = 0; i < ARRAY_SIZE(rate); i++) {
+		if (rate[i] > max_rate)
+			continue;
+		/* Fill the bw related input parameters */
+		frl_dfm.config.lanes = rate[i] < 24 ? 3 : 4;
+		frl_dfm.config.bit_rate_kbps = (rate[i] * 1000000) / frl_dfm.config.lanes;
+		for (j = 0; j < ARRAY_SIZE(audio_freq_hz); j++) {
+			frl_dfm.config.audio_hz = audio_freq_hz[j];
+			frl_dfm.config.audio_channels = 8;
+
+			if (intel_hdmi_frl_dfm_nondsc_requirement_met(&frl_dfm)) {
+				can_support_frl_mode = true;
+				break;
+			}
+		}
+
+		if (can_support_frl_mode)
+			break;
+	}
+
+	if (!can_support_frl_mode)
+		return -EINVAL;
+
+	/* Fill crtc_state frl DFM output params */
+	crtc_state->frl.required_lanes = frl_dfm.config.lanes;
+	crtc_state->frl.required_rate = frl_dfm.config.bit_rate_kbps / 1000000;
+	crtc_state->frl.tb_borrowed = frl_dfm.params.tb_borrowed;
+	crtc_state->frl.tb_actual = frl_dfm.params.tb_borrowed / 2;
+	drm_dbg_kms(display->drm, "FRL DFM config: tb_borrowed = %d, tb_actual = %d\n",
+		    crtc_state->frl.tb_borrowed, crtc_state->frl.tb_actual);
+
+	if (frl_dfm.params.tb_borrowed && (frl_dfm.params.tb_borrowed / 2) <= 492)
+		crtc_state->frl.tb_threshold_min = 492 - (frl_dfm.params.tb_borrowed / 2);
+	else
+		crtc_state->frl.tb_threshold_min = 492;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
index 1bfc70067518..eedf43e2836c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 
 struct intel_crtc_state;
+struct intel_encoder;
 
 /* All the input config needed to compute DFM requirements */
 struct intel_hdmi_frl_dfm_input_config {
@@ -119,5 +120,7 @@ intel_hdmi_frl_dfm_dsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm);
 
 void intel_hdmi_frl_dfm_write(const struct intel_crtc_state *crtc_state);
 void intel_hdmi_frl_dfm_read(struct intel_crtc_state *crtc_state);
+int intel_hdmi_frl_dfm_compute_config(struct intel_encoder *encoder,
+				      struct intel_crtc_state *crtc_state);
 
 #endif
-- 
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.