From: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
To: intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org, jani.nikula@linux.intel.com,
uma.shankar@intel.com, ville.syrjala@linux.intel.com,
suraj.kandpal@intel.com
Subject: [PATCH 33/44] drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC
Date: Fri, 7 Aug 2026 09:44:18 +0530 [thread overview]
Message-ID: <20260807041430.229038-34-ankit.k.nautiyal@intel.com> (raw)
In-Reply-To: <20260807041430.229038-1-ankit.k.nautiyal@intel.com>
Add helper functions for calculating FRL capacity and DFM
requirements with given compressed bpp.
v2: Fix misc issues seen while testing (Mitul)
- Utilization reuirement for DSC should return true
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Mitul Golani <mitulkumar.ajitkumar.golani@intel.com>
---
.../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 289 ++++++++++++++++++
.../gpu/drm/i915/display/intel_hdmi_frl_dfm.h | 3 +
2 files changed, 292 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 2de9d3dd23ae..56ade6009983 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
@@ -413,3 +413,292 @@ intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm)
return false;
}
+
+/* Get required no. of tribytes (estimate1) during HCBlank */
+static u32
+get_frl_hcblank_tb_est1_target(u32 hcactive_target_tb,
+ u32 hactive, u32 hblank)
+{
+ return DIV_ROUND_UP(hcactive_target_tb * hblank, hactive);
+}
+
+/* Get required no. of tribytes during HCBlank */
+static u32
+get_frl_hcblank_tb_target(u32 hcactive_target_tb, u32 hactive,
+ u32 hblank, u32 hcblank_audio_min,
+ u32 cfrl_available)
+{
+ u32 hcblank_target_tb1 = get_frl_hcblank_tb_est1_target(hcactive_target_tb,
+ hactive, hblank);
+ u32 hcblank_target_tb2 = max(hcblank_target_tb1, hcblank_audio_min);
+
+ return 4 * (min(hcblank_target_tb2,
+ (2 * cfrl_available - 3 * hcactive_target_tb) / 2) / 4);
+}
+
+static u32
+get_dsc_tribyte_time(u32 num_tribyte,
+ u32 tribyte_rate_k)
+{
+ u32 tribyte_time, time_multiplier;
+
+ /*
+ * tribyte_rate_k is the num of kilo tribytes in 1 sec, on an average.
+ *
+ * time taken for:
+ * (tribyte_rate_k * 1000) tribytes -> 1 sec
+ * (tribyte_rate_k * 1000) tribytes -> 10^9 nsec
+ * 1000 tribytes -> (10^9 / tribyte_rate_k) nsec
+ * 1 tribyte -> 10^9 / tribyte_rate_k * 1000)
+ * 1 tribyte -> 10^6 / tribyte_rate_k
+ * tribyte_time -> num_tribyte * 10 ^ 6 / (tribyte_rate_k)
+ *
+ * So, avg time for tribyte_time in nsec =
+ * num_tribyte * 10 ^ 6 / (tribyte_rate_k)
+ */
+ time_multiplier = DIV_ROUND_UP(FRL_TIMING_NS_MULTIPLIER, 1000);
+ tribyte_time = num_tribyte * time_multiplier;
+
+ return DIV_ROUND_UP(tribyte_time, tribyte_rate_k);
+}
+
+/* Get time to send all tribytes in hcactive region in nsec*/
+static u32
+get_dsc_tactive_target_ns(u32 frl_lanes, u32 hcactive_target_tb,
+ u32 ftb_avg_k, u32 min_frl_char_rate_k,
+ u32 overhead_max)
+{
+ u32 avg_tribyte_time_ns, tribyte_time_ns;
+ u32 num_chars_hcactive;
+ u32 frl_char_rate_k;
+
+ /* Avg time to transmit all active region tribytes */
+ avg_tribyte_time_ns = get_dsc_tribyte_time(hcactive_target_tb, ftb_avg_k);
+
+ /*
+ * 2 bytes in active region = 1 FRL characters
+ * 1 Tribyte in active region = 3/2 FRL characters
+ */
+ num_chars_hcactive = DIV_ROUND_UP(hcactive_target_tb * 3, 2);
+
+ /*
+ * FRL rate = lanes * frl character rate
+ * But actual bandwidth wil be less, due to FRL limitations so account
+ * for the overhead involved.
+ * FRL rate with overhead = FRL rate * (100 - overhead %) / 100
+ */
+ frl_char_rate_k = frl_lanes * min_frl_char_rate_k;
+ frl_char_rate_k = DIV_ROUND_UP(frl_char_rate_k * (EFFICIENCY_MULTIPLIER - overhead_max),
+ EFFICIENCY_MULTIPLIER);
+
+ /* Time to transmit all characters with FRL limitations */
+ tribyte_time_ns = get_dsc_tribyte_time(num_chars_hcactive, frl_char_rate_k);
+ return max(avg_tribyte_time_ns, tribyte_time_ns);
+}
+
+/* Get TBdelta : borrowing in tribytes relative to avg tribyte rate */
+static u32
+get_dsc_tri_bytes_delta(u32 tactive_target_ns, u32 tblank_target_ns,
+ u32 tactive_ref_ns, u32 tblank_ref_ns,
+ u32 hcactive_target_tb, u32 ftb_avg_k,
+ u32 hactive, u32 hblank,
+ u32 line_time_ns)
+{
+ u32 tb_delta_limit;
+ u32 hcblank_target_tb1 = get_frl_hcblank_tb_est1_target(hcactive_target_tb,
+ hactive, hblank);
+ u32 tribytes = (hcactive_target_tb + hcblank_target_tb1);
+ u32 tactive_avg_ns;
+
+ if (tblank_ref_ns < tblank_target_ns) {
+ tactive_avg_ns = mult_frac(FRL_TIMING_NS_MULTIPLIER,
+ hcactive_target_tb, ftb_avg_k * 1000);
+ tb_delta_limit = DIV_ROUND_UP((tactive_ref_ns - tactive_avg_ns) * tribytes,
+ line_time_ns);
+ } else {
+ u32 t_delta_ns;
+
+ if (tactive_target_ns > tactive_ref_ns)
+ t_delta_ns = tactive_target_ns - tactive_ref_ns;
+ else
+ t_delta_ns = tactive_ref_ns - tactive_target_ns;
+ tb_delta_limit = (t_delta_ns * tribytes) / line_time_ns;
+ }
+
+ return tb_delta_limit;
+}
+
+static u32
+get_dsc_tri_bytes_borrowed(u32 ftb_avg_k,
+ u32 tactive_target_ns,
+ u32 hcactive_target)
+{
+ u32 hactive, tb_borrowed;
+
+ hactive = DIV_ROUND_UP(tactive_target_ns * DIV_ROUND_UP(ftb_avg_k, 1000), 1000);
+ tb_borrowed = hactive - hcactive_target;
+
+ return tb_borrowed;
+}
+
+/* Compute hcactive and hcblank tribytes for given dsc bpp setting */
+static void
+compute_dsc_tribytes(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+ u32 hcactive_target_tb;
+ u32 hcblank_target_tb;
+ u32 cfrl_available;
+ u32 num_slices;
+ u32 bytes_target;
+
+ /* Assert for slice width ?*/
+ if (!frl_dfm->config.slice_width)
+ return;
+
+ num_slices = DIV_ROUND_UP(frl_dfm->config.hactive, frl_dfm->config.slice_width);
+
+ /* Get required no. of tribytes during HCActive */
+ bytes_target = num_slices *
+ DIV_ROUND_UP(frl_dfm->config.target_bpp_16 * frl_dfm->config.slice_width,
+ 8 * BPP_MULTIPLIER);
+
+ hcactive_target_tb = DIV_ROUND_UP(bytes_target, 3);
+
+ /* Get FRL Available characters */
+ cfrl_available = ((EFFICIENCY_MULTIPLIER - frl_dfm->params.overhead_max) *
+ frl_dfm->params.cfrl_line) / EFFICIENCY_MULTIPLIER;
+
+ hcblank_target_tb =
+ get_frl_hcblank_tb_target(hcactive_target_tb,
+ frl_dfm->config.hactive,
+ frl_dfm->config.hblank,
+ frl_dfm->params.hblank_audio_min,
+ cfrl_available);
+
+ frl_dfm->params.hcactive_target = hcactive_target_tb;
+ frl_dfm->params.hcblank_target = hcblank_target_tb;
+}
+
+/* Check if audio supported with given dsc bpp and frl bandwidth */
+static bool
+audio_supported_with_dsc(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+ return frl_dfm->params.hcblank_target > frl_dfm->params.hblank_audio_min;
+}
+
+/* Is DFM timing requirement is met with DSC */
+static
+bool timing_req_met_with_dsc(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+ u32 ftb_avg_k;
+ u32 tactive_ref_ns, tblank_ref_ns, tactive_target_ns, tblank_target_ns;
+ u32 tb_borrowed, tb_delta, tb_worst;
+
+ /* Get the avg no of tribytes sent per sec (Kbps) */
+ ftb_avg_k = (frl_dfm->params.hcactive_target + frl_dfm->params.hcblank_target) *
+ DIV_ROUND_UP(frl_dfm->params.pixel_clock_max_khz,
+ frl_dfm->config.hactive + frl_dfm->config.hblank);
+
+ /* Time to send Active tribytes in nanoseconds */
+ tactive_ref_ns = DIV_ROUND_UP(frl_dfm->params.line_time_ns * frl_dfm->config.hactive,
+ frl_dfm->config.hactive + frl_dfm->config.hblank);
+
+ /* Time to send Blanking tribytes in nanoseconds */
+ tblank_ref_ns = DIV_ROUND_UP(frl_dfm->params.line_time_ns * frl_dfm->config.hblank,
+ frl_dfm->config.hactive + frl_dfm->config.hblank);
+
+ tactive_target_ns = get_dsc_tactive_target_ns(frl_dfm->config.lanes,
+ frl_dfm->params.hcactive_target,
+ ftb_avg_k,
+ frl_dfm->params.char_rate_min_kbps,
+ frl_dfm->params.overhead_max);
+
+ tblank_target_ns = frl_dfm->params.line_time_ns - tactive_target_ns;
+
+ /* Get no. of tri bytes borrowed with DSC enabled */
+ tb_borrowed = get_dsc_tri_bytes_borrowed(ftb_avg_k,
+ tactive_target_ns,
+ frl_dfm->params.hcactive_target);
+
+ tb_delta = get_dsc_tri_bytes_delta(tactive_target_ns,
+ tblank_target_ns,
+ tactive_ref_ns,
+ tblank_ref_ns,
+ frl_dfm->params.hcactive_target,
+ ftb_avg_k,
+ frl_dfm->config.hactive,
+ frl_dfm->config.hblank,
+ frl_dfm->params.line_time_ns);
+
+ tb_worst = max(tb_borrowed, tb_delta);
+ if (tb_worst > TB_BORROWED_MAX)
+ return false;
+
+ frl_dfm->params.ftb_avg_k = ftb_avg_k;
+ frl_dfm->params.tb_borrowed = tb_borrowed;
+
+ return true;
+}
+
+/* Check Utilization constraint with DSC */
+static bool
+utilization_constraints_met_with_dsc(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+ u32 hcactive_target_tb = frl_dfm->params.hcactive_target;
+ u32 hcblank_target_tb = frl_dfm->params.hcblank_target;
+ u32 frl_char_per_line = frl_dfm->params.cfrl_line;
+ u32 overhead_max = frl_dfm->params.overhead_max;
+ u32 utilization_with_overhead;
+ u32 actual_frl_char_payload;
+ u32 utilization;
+
+ /*
+ * Note:
+ * 1 FRL characters per 2 bytes in active period
+ * 1 FRL char per byte in Blanking period
+ */
+ actual_frl_char_payload = DIV_ROUND_UP(3 * hcactive_target_tb, 2) +
+ hcblank_target_tb;
+
+ utilization = (actual_frl_char_payload * EFFICIENCY_MULTIPLIER) /
+ frl_char_per_line;
+
+ /*
+ * Utilization with overhead = utlization% +overhead %
+ * should be less than 100%
+ */
+ utilization_with_overhead = utilization + overhead_max;
+ if (utilization_with_overhead > EFFICIENCY_MULTIPLIER)
+ return false;
+
+ return true;
+}
+
+/*
+ * intel_hdmi_frl_dfm_dsc_requirement_met : Check if FRL DFM requirements are met with
+ * the given bpp.
+ * @frl_dfm: dfm structure
+ *
+ * Returns true if the frl dfm requirements are met, else returns false.
+ */
+bool intel_hdmi_frl_dfm_dsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm)
+{
+ if (!frl_dfm->config.slice_width || !frl_dfm->config.target_bpp_16)
+ return false;
+
+ compute_max_frl_link_overhead(frl_dfm);
+ compute_link_characteristics(frl_dfm);
+ compute_audio_hblank_min(frl_dfm);
+ compute_dsc_tribytes(frl_dfm);
+
+ if (!audio_supported_with_dsc(frl_dfm))
+ return false;
+
+ if (!timing_req_met_with_dsc(frl_dfm))
+ return false;
+
+ if (!utilization_constraints_met_with_dsc(frl_dfm))
+ return false;
+
+ return true;
+}
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 83d5b0d6370b..70a66679bdbc 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
@@ -112,4 +112,7 @@ struct intel_hdmi_frl_dfm {
bool intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm);
+bool
+intel_hdmi_frl_dfm_dsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm);
+
#endif
--
2.50.1
next prev parent reply other threads:[~2026-08-07 4:32 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-07 4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt Ankit Nautiyal
2026-09-02 6:52 ` Kandpal, Suraj
2026-09-02 7:20 ` Jani Nikula
2026-08-07 4:13 ` [PATCH 02/44] drm/i915/hdmi: Add new data members for FRL configuration Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 03/44] drm/i915/hdmi: Add FRL link rate cap Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 04/44] drm/drm_scdc_helper: Add SCDC helper funcs for FRL Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 05/44] drm/i915/display: Add registers for HDMI FRL configuration Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 06/44] drm/i915/display: Add new members in crtc_state for " Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 07/44] drm/i915/intel_cx0_phy_regs: Add HDMI FRL SHIFT EN bit in PORT_BUF_CTL_1 Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 08/44] drm/i915/ddi: Update Transcoder/DDI registers with the frl bits Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 09/44] drm/i915/hdmi: Enable Scrambling only for TMDS mode Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 10/44] drm/i915/ddi: Simplify intel_ddi_enable() Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 11/44] drm/i915/ddi: Factor out common transcoder/vblank enable sequence Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 12/44] drm/i915/ddi: Update HDMI modeset sequence for MTL+ Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 13/44] drm/i915/hdmi: Add function to prepare registers for FRL mode Ankit Nautiyal
2026-08-07 4:13 ` [PATCH 14/44] drm/i915/hdmi: Add functions for FRL training state machine Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 15/44] drm/i915/intel_hdmi: Add helper to disable FRL Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 16/44] drm/i915/hdmi: Reduce FRL rate cap on rate change during training Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 17/44] drm/i915/hdmi: Introduce intel_hdmi_frl_level() for per-lane TxFFE Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 18/44] drm/i915/hdmi: Drive per-lane TxFFE during FRL link training Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 19/44] drm/i915/ltphy: Add PLL tables for HDMI FRL Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 20/44] drm/i915/ltphy: Add safegaurd when calculation HDMI FRL state Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 21/44] drm/i915/ltphy: Calculate port clock for HDMI FRL Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 22/44] drm/i915/ltphy: Verify HDMI FRL tables Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 23/44] drm/i915/ddi_buf: Add Vswing table for HDMI FRL Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 24/44] drm/i915/hdmi: Add provision for FRL mode while computing output format Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 25/44] drm/i915/hdmi: Rename port clock limit to specify tmds clock Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 26/44] drm/i915/cx0: Add helper to check if the FRL rate is valid Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 27/44] drm/i915/lt_phy: " Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 28/44] drm/i915/hdmi: Rename port clock valid to specify tmds clock Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 29/44] drm/i915/hdmi: Add FRL port and mode clock valid Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 30/44] drm/i915/hdmi_frl_dfm_regs: Define DFM registers Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 31/44] drm/i915/hdmi_frl_dfm: Define frl_dfm structure Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 32/44] drm/i915/hdmi_frl_dfm: Add non dsc frl capacity computation helpers Ankit Nautiyal
2026-08-07 4:14 ` Ankit Nautiyal [this message]
2026-08-07 4:14 ` [PATCH 34/44] drm/i915/hdmi: Add helper to write FRL CFG register Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 35/44] drm/i915/hdmi_frl_dfm: Add helpers to read/write FRL DFM registers Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 36/44] drm/i915/hdmi_frl_dfm: Add function to compute FRL DFM config Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 37/44] drm/i915/hdmi: Add FRL clock computation based on DFM Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 38/44] drm/i915/hdmi: Add support for sending uevent to user for FRL training failure Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 39/44] drm/i915/ddi: Wire FRL into the HDMI DDI enable/disable path Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 40/44] drm/i915/hdmi: Add read out for FRL state Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 41/44] drm/i915/hdmi_frl_dfm: Handle FRL Link M/N Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 42/44] drm/i915/display: Add FRL members to the state checker Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 43/44] drm/i915/hdmi: Compute output format for HDMI FRL mode Ankit Nautiyal
2026-08-07 4:14 ` [PATCH 44/44] drm/i915/hdmi: Enable FRL based mode clock valid Ankit Nautiyal
2026-08-07 15:32 ` ✓ i915.CI.BAT: success for Enable HDMI FRL for MTL+ Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260807041430.229038-34-ankit.k.nautiyal@intel.com \
--to=ankit.k.nautiyal@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=jani.nikula@linux.intel.com \
--cc=suraj.kandpal@intel.com \
--cc=uma.shankar@intel.com \
--cc=ville.syrjala@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox