[PATCH 32/44] drm/i915/hdmi_frl_dfm: Add non dsc frl capacity computation helpers

Ankit Nautiyal <[email protected]>
Newsgroups org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-gfx,org.freedesktop.lists.intel-xe
Message-ID <[email protected]>
From: Vandita Kulkarni <[email protected]>

Add helper functions for computing non dsc frl
link characteristics

Signed-off-by: Vandita Kulkarni <[email protected]>
Signed-off-by: Ankit Nautiyal <[email protected]>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 415 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h |   2 +
 drivers/gpu/drm/xe/Makefile                   |   1 +
 4 files changed, 419 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a83fa8be0aba..016816bbfc4b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -367,6 +367,7 @@ i915-y += \
 	display/intel_encoder.o \
 	display/intel_gmbus.o \
 	display/intel_hdmi.o \
+	display/intel_hdmi_frl_dfm.o \
 	display/intel_lspcon.o \
 	display/intel_lt_phy.o \
 	display/intel_lvds.o \
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
new file mode 100644
index 000000000000..2de9d3dd23ae
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corp
+ */
+
+#include <linux/kernel.h>
+
+#include <drm/drm_connector.h>
+
+#include "intel_hdmi_frl_dfm.h"
+
+/* DFM constraints and tolerance values */
+#define TB_BORROWED_MAX			400
+#define FRL_CHAR_PER_CHAR_BLK		510
+/* Tolerance pixel clock unit is in  mHz */
+#define TOLERANCE_PIXEL_CLOCK		5
+#define TOLERANCE_FRL_BIT_RATE		300
+#define TOLERANCE_AUDIO_CLOCK		1000
+#define ACR_RATE_MAX			1500
+#define EFFICIENCY_MULTIPLIER		1000
+#define OVERHEAD_M			(3 * EFFICIENCY_MULTIPLIER / 1000)
+#define BPP_MULTIPLIER			16
+#define FRL_TIMING_NS_MULTIPLIER	1000000000
+
+/* Total FRL characters per super block */
+static u32 get_frl_char_per_super_blk(u32 lanes)
+{
+	return (4 * FRL_CHAR_PER_CHAR_BLK) + lanes;
+}
+
+/* Total minimum overhead multiplied by EFFICIENCY_MULIPLIER */
+static u32 get_total_minimum_overhead(u32 lanes)
+{
+	u32 overhead_sb;
+	u32 overhead_rs;
+	u32 overhead_map;
+
+	/*
+	 * Determine the overhead due to the inclusion of
+	 * the SR and SSB FRL characters used for
+	 * super block framing
+	 */
+	overhead_sb = (lanes * EFFICIENCY_MULTIPLIER) / get_frl_char_per_super_blk(lanes);
+
+	/*
+	 * Determine the overhead due to the inclusion of RS FEC pairity
+	 * symbols. Each character block uses 8 FRL characters for RS Pairity
+	 * and there are 4 character blocks per super block
+	 */
+	overhead_rs = (8 * 4 * EFFICIENCY_MULTIPLIER) /  get_frl_char_per_super_blk(lanes);
+
+	/*
+	 * Determine the overhead due to FRL Map characters.
+	 * In a bandwidth constrained application, the FRL packets will be long,
+	 * there will typically be two FRL Map Characters per Super Block most of the time.
+	 * When a tracnsition occurs between Hactive and Hblank (uncomperssed video) or
+	 * HCactive and HCblank (compressed video transport), there may be a
+	 * third FRL Map Charecter. Therefore this spec assumes 2.5 FRL Map Characters
+	 * per Super Block.
+	 */
+	overhead_map =
+		(25  * EFFICIENCY_MULTIPLIER) / (10 * get_frl_char_per_super_blk(lanes));
+
+	return overhead_sb + overhead_rs + overhead_map;
+}
+
+/* Audio Support Verification Computations */
+
+/*
+ * During the Hblank period, Audio packets (32 frl characters each),
+ * ACR packets (32 frl characters each), Island guard band (4 total frl characters)
+ * and Video guard band (3 frl characters) do not benefit from RC compression
+ * Therefore start by determining the number of Control Characters that maybe
+ * RC compressible
+ */
+static u32
+get_num_char_rc_compressible(u32 color_format, u32 bpc,
+			     u32 audio_packets_line, u32 hblank)
+{
+	u32 cfrl_free;
+	u32 kcdx100, k420;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420)
+		k420 = 2;
+	else
+		k420 = 1;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422)
+		kcdx100 = 100;
+	else
+		kcdx100 = (100 * bpc) / 8;
+
+	cfrl_free = max(((hblank * kcdx100) / (100 * k420) - 32 * audio_packets_line - 7),
+			U32_MIN);
+
+	return cfrl_free;
+}
+
+/*
+ * Determine the actual number of characters made available by
+ * RC compression
+ */
+static u32
+get_num_char_compression_savings(u32 cfrl_free)
+{
+	/*
+	 * In order to be conservative, situations are considered where
+	 * maximum RC compression may not be possible.
+	 * Add one character each for RC break caused by:
+	 * • Island Preamble not aligned to the RC Compression
+	 * • Video Preamble not aligned to the RC Compression
+	 * • HSYNC lead edge not aligned to the RC Compression
+	 * • HSYNC trail edge not aligned to the RC Compression
+	 */
+	const u32 cfrl_margin = 4;
+	u32 cfrl_savings = max(((7 * cfrl_free) / 8) - cfrl_margin, U32_MIN);
+
+	return cfrl_savings;
+}
+
+static u32
+get_frl_bits_per_pixel(u32 color_format, u32 bpc)
+{
+	u32 kcdx100, k420;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420)
+		k420 = 2;
+	else
+		k420 = 1;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422)
+		kcdx100 = 100;
+	else
+		kcdx100 = (100 * bpc) / 8;
+
+	return (24 * kcdx100) / (100 * k420);
+}
+
+/* Determine the total available tribytes during the blanking period */
+static u32
+get_blanking_tribytes_avail(u32 color_format,
+			    u32 hblank, u32 bpc)
+{
+	u32 kcdx100, k420;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420)
+		k420 = 2;
+	else
+		k420 = 1;
+
+	if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422)
+		kcdx100 = 100;
+	else
+		kcdx100 = (100 * bpc) / 8;
+
+	return DIV_ROUND_UP((hblank * kcdx100), (100 * k420));
+}
+
+/*
+ * Determine the minimum time necessary to transmit the active tribytes
+ * considering frl bandwidth limitation.
+ * Given the available bandwidth (i.e after overhead is considered),
+ * tactive_min represents the amount of time needed to transmit all the
+ * active data
+ */
+static u32
+get_tactive_min(u32 num_lanes, u32 tribyte_active,
+		u32 overhead_max_k, u32 frl_char_min_rate_k)
+{
+	u32 active_bytes, rate_kbps, efficiency_k, effective_rate_kbps;
+
+	active_bytes = (3 * tribyte_active) / 2;
+	rate_kbps = num_lanes * frl_char_min_rate_k;
+	efficiency_k = EFFICIENCY_MULTIPLIER - overhead_max_k;
+	effective_rate_kbps = mult_frac(rate_kbps, efficiency_k, EFFICIENCY_MULTIPLIER);
+
+	return mult_frac(FRL_TIMING_NS_MULTIPLIER, active_bytes, effective_rate_kbps) / 1000;
+}
+
+/*
+ * Determine the minimum time necessary to transmit the video blanking
+ * tribytes considering frl bandwidth limitations
+ */
+static u32
+get_tblank_min(u32 num_lanes, u32 tribyte_blank,
+	       u32 overhead_max_k, u32 frl_char_min_rate_k)
+{
+	u32 blank_bytes, rate_kbps, efficiency_k, effective_rate_kbps;
+
+	blank_bytes = (3 * tribyte_blank) / 2;
+	rate_kbps = num_lanes * frl_char_min_rate_k;
+	efficiency_k = EFFICIENCY_MULTIPLIER - overhead_max_k;
+	effective_rate_kbps = mult_frac(rate_kbps, efficiency_k, EFFICIENCY_MULTIPLIER);
+
+	return mult_frac(FRL_TIMING_NS_MULTIPLIER, blank_bytes, effective_rate_kbps) / 1000;
+}
+
+/* Collect link characteristics */
+static void
+compute_link_characteristics(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 frl_bit_rate_min_kbps, line_width, rate_m;
+
+	/* Determine the maximum legal pixel rate */
+	frl_dfm->params.pixel_clock_max_khz =
+		(frl_dfm->config.pixel_clock_nominal_khz * (1000 + TOLERANCE_PIXEL_CLOCK)) / 1000;
+
+	/* Determine the minimum Video Line period */
+	line_width = frl_dfm->config.hactive + frl_dfm->config.hblank;
+
+	frl_dfm->params.line_time_ns = mult_frac(FRL_TIMING_NS_MULTIPLIER,
+						 line_width,
+						 frl_dfm->params.pixel_clock_max_khz) / 1000;
+
+	/* Determine the worst-case slow FRL Bit Rate in kbps*/
+	frl_bit_rate_min_kbps =
+		(frl_dfm->config.bit_rate_kbps / 1000000) * (1000000 - TOLERANCE_FRL_BIT_RATE);
+
+	/* Determine the worst-case slow FRL Character Rate */
+	frl_dfm->params.char_rate_min_kbps = frl_bit_rate_min_kbps / 18;
+
+	/* Character rate in mega chars/sec */
+	rate_m = DIV_ROUND_UP(frl_dfm->params.char_rate_min_kbps * frl_dfm->config.lanes, 1000);
+
+	/* Determine the Minimum Total FRL characters per line period */
+	frl_dfm->params.cfrl_line = DIV_ROUND_UP(frl_dfm->params.line_time_ns * rate_m,
+						 FRL_TIMING_NS_MULTIPLIER / 1000000);
+}
+
+/* Determine FRL link overhead */
+static void compute_max_frl_link_overhead(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 overhead_min = get_total_minimum_overhead(frl_dfm->config.lanes);
+
+	/*
+	 * Additional margin to the overhead is provided to account for the possibility
+	 * of more Map Characters, zero padding at the end of HCactive, and other minor
+	 * items
+	 */
+	frl_dfm->params.overhead_max = overhead_min + OVERHEAD_M;
+}
+
+/* Audio support Verification computations */
+static void
+compute_audio_hblank_min(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 num_audio_pkt, audio_pkt_rate;
+
+	/*
+	 * #TODO: get the actual audio pkt type to find the num_audio_pkt.
+	 * For now assume audio sample packet and audio packet layout as 1,
+	 * resulting in number of audio packets required to carry each
+	 * audio sample or audio frame as 1.
+	 */
+	num_audio_pkt = 1;
+
+	/*
+	 * Determine Audio Related Packet Rate considering the audio clock
+	 * increased to maximim rate permitted by Tolerance Audio clock
+	 */
+	audio_pkt_rate =
+		((frl_dfm->config.audio_hz *  num_audio_pkt + (2 * ACR_RATE_MAX)) *
+		 (1000000 + TOLERANCE_AUDIO_CLOCK)) / 1000000;
+
+	/*
+	 * Average required packets per line is
+	 * number of audio packets needed during Hblank
+	 */
+	frl_dfm->params.num_audio_pkts_line =
+		DIV_ROUND_UP(audio_pkt_rate * frl_dfm->params.line_time_ns,
+			     FRL_TIMING_NS_MULTIPLIER);
+
+	/*
+	 * Minimum required Hblank assuming no Control Period RC Compression
+	 * This includes Video Guard band, Two Island Guard bands, two 12 character
+	 * Control Periods and 32 * AudioPackets_Line.
+	 * In addition, 32 character periods are allocated for the transmission of an
+	 * ACR packet
+	 */
+	frl_dfm->params.hblank_audio_min = 32 + 32 * frl_dfm->params.num_audio_pkts_line;
+}
+
+/*
+ * Determine the number of tribytes required for active video , blanking period
+ * with the pixel configuration
+ */
+static void
+compute_tbactive_tbblank(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 bpp, bytes_per_line;
+
+	bpp = get_frl_bits_per_pixel(frl_dfm->config.color_format, frl_dfm->config.bpc);
+	bytes_per_line = (bpp * frl_dfm->config.hactive) / 8;
+
+	frl_dfm->params.tb_active = DIV_ROUND_UP(bytes_per_line, 3);
+
+	frl_dfm->params.tb_blank =
+		get_blanking_tribytes_avail(frl_dfm->config.color_format,
+					    frl_dfm->config.hblank,
+					    frl_dfm->config.bpc);
+}
+
+/* Verify the configuration meets the capacity requirements for the FRL configuration*/
+static bool
+verify_frl_capacity_requirement(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 tactive_ref_ns, tblank_ref_ns, tactive_min_ns, tblank_min_ns;
+	u32 tborrowed_ns;
+	u32 line_time_ns = frl_dfm->params.line_time_ns;
+	u32 hactive = frl_dfm->config.hactive;
+	u32 hblank = frl_dfm->config.hblank;
+
+	/* Determine the average tribyte rate in kilo tribytes per sec */
+	frl_dfm->params.ftb_avg_k =
+		(frl_dfm->params.pixel_clock_max_khz *
+		 (frl_dfm->params.tb_active + frl_dfm->params.tb_blank)) /
+		(frl_dfm->config.hactive + frl_dfm->config.hblank);
+
+	/*
+	 * Determine the time required to transmit the active portion of the
+	 * minimum possible active line period in the base timing
+	 */
+	tactive_ref_ns = (line_time_ns * hactive) / (hblank + hactive);
+
+	/*
+	 * Determine the time required to transmit the Video blanking portion
+	 * of the minimum possible active line period in the base timing
+	 */
+	tblank_ref_ns = (line_time_ns * hblank) / (hblank + hactive);
+
+	tactive_min_ns = get_tactive_min(frl_dfm->config.lanes,
+					 frl_dfm->params.tb_active,
+					 frl_dfm->params.overhead_max,
+					 frl_dfm->params.char_rate_min_kbps);
+	tblank_min_ns = get_tblank_min(frl_dfm->config.lanes,
+				       frl_dfm->params.tb_blank,
+				       frl_dfm->params.overhead_max,
+				       frl_dfm->params.char_rate_min_kbps);
+
+	if (tactive_ref_ns >= tactive_min_ns &&
+	    tblank_ref_ns >= tblank_min_ns) {
+		tborrowed_ns = 0;
+		frl_dfm->params.tb_borrowed = 0;
+
+		return true;
+	}
+
+	if (tactive_ref_ns < tactive_min_ns &&
+	    tblank_ref_ns >= tblank_min_ns) {
+		tborrowed_ns = tactive_min_ns - tactive_ref_ns;
+		/* Determine the disparity in tribytes */
+		frl_dfm->params.tb_borrowed =
+			DIV_ROUND_UP((tborrowed_ns * frl_dfm->params.ftb_avg_k * 1000),
+				     FRL_TIMING_NS_MULTIPLIER);
+
+		if (frl_dfm->params.tb_borrowed <= TB_BORROWED_MAX)
+			return true;
+	}
+
+	return false;
+}
+
+/* Verify utilization does not exceed capacity */
+static bool
+verify_utilization_possible(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	u32 cfrl_free, cfrl_savings, frl_char_payload_actual;
+	u32 utilization, margin;
+
+	cfrl_free = get_num_char_rc_compressible(frl_dfm->config.color_format,
+						 frl_dfm->config.bpc,
+						 frl_dfm->params.num_audio_pkts_line,
+						 frl_dfm->config.hblank);
+	cfrl_savings = get_num_char_compression_savings(cfrl_free);
+
+	/*
+	 * Determine the actual number of payload FRL characters required to
+	 * carry each video line
+	 */
+	frl_char_payload_actual =
+		DIV_ROUND_UP(3 * frl_dfm->params.tb_active, 2) +
+		frl_dfm->params.tb_blank - cfrl_savings;
+
+	/*
+	 * Determine the payload utilization of the total number of
+	 * FRL characters
+	 */
+	utilization = (frl_char_payload_actual * EFFICIENCY_MULTIPLIER) / frl_dfm->params.cfrl_line;
+
+	margin = 1000 - (utilization + frl_dfm->params.overhead_max);
+
+	if (margin > 0)
+		return true;
+
+	return false;
+}
+
+/* Check if DFM requirement is met */
+bool
+intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+	bool frl_capacity_req_met;
+
+	compute_max_frl_link_overhead(frl_dfm);
+	compute_link_characteristics(frl_dfm);
+	compute_audio_hblank_min(frl_dfm);
+	compute_tbactive_tbblank(frl_dfm);
+
+	frl_capacity_req_met = verify_frl_capacity_requirement(frl_dfm);
+
+	if (frl_capacity_req_met)
+		return verify_utilization_possible(frl_dfm);
+
+	return false;
+}
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 c619073eef9b..83d5b0d6370b 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
@@ -110,4 +110,6 @@ struct intel_hdmi_frl_dfm {
 	struct intel_hdmi_frl_dfm_params params;
 };
 
+bool intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm);
+
 #endif
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 44ed055439d4..7c1c83072851 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -303,6 +303,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
 	i915-display/intel_hdcp.o \
 	i915-display/intel_hdcp_gsc_message.o \
 	i915-display/intel_hdmi.o \
+	i915-display/intel_hdmi_frl_dfm.o \
 	i915-display/intel_hotplug.o \
 	i915-display/intel_hotplug_irq.o \
 	i915-display/intel_hti.o \
-- 
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.