Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/44] Enable HDMI FRL for MTL+
@ 2026-08-07  4:13 Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt Ankit Nautiyal
                   ` (44 more replies)
  0 siblings, 45 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

This series adds support for HDMI Fixed Rate Link (FRL) on MTL+ platforms.
FRL is a high-bandwidth transmission mode required for modes that exceed
the TMDS bandwidth limit.

The series covers the core enabling:
- SCDC helper additions for FRL link training
- FRL link training state machine (LTS:2, LTS:3, LTS:P)
- DDI enable/disable sequence updates for FRL mode
- DFM (Data Flow Metering) computation and register programming
- PHY (CX0/LT PHY) support for FRL rates
- Mode validation and clock computation for FRL

This is a work in progress. The primary goal at this stage is to get the
overall design reviewed and the foundational patches landed before building
on top.

Lightly tested on PTL. Modes like 4K@120 are working. Higher resolution
modes (e.g. 8K) require DSC which is not yet covered in this series, that
work is ongoing.

Testing on other MTL+ platforms is also ongoing.
Known gaps:
- DSC over FRL not yet supported
- Testing limited to MTL, PTL so far

Feedback on the design and approach is welcome.

Ankit Nautiyal (28):
  drm/i915/hdmi: Add new data members for FRL configuration
  drm/i915/hdmi: Add FRL link rate cap
  drm/drm_scdc_helper: Add SCDC helper funcs for FRL
  drm/i915/display: Add registers for HDMI FRL configuration
  drm/i915/display: Add new members in crtc_state for FRL configuration
  drm/i915/intel_cx0_phy_regs: Add HDMI FRL SHIFT EN bit in
    PORT_BUF_CTL_1
  drm/i915/ddi: Update Transcoder/DDI registers with the frl bits
  drm/i915/hdmi: Enable Scrambling only for TMDS mode
  drm/i915/ddi: Simplify intel_ddi_enable()
  drm/i915/ddi: Factor out common transcoder/vblank enable sequence
  drm/i915/ddi: Update HDMI modeset sequence for MTL+
  drm/i915/hdmi: Add function to prepare registers for FRL mode
  drm/i915/hdmi: Add functions for FRL training state machine
  drm/i915/intel_hdmi: Add helper to disable FRL
  drm/i915/hdmi: Reduce FRL rate cap on rate change during training
  drm/i915/hdmi: Add provision for FRL mode while computing output
    format
  drm/i915/cx0: Add helper to check if the FRL rate is valid
  drm/i915/lt_phy: Add helper to check if the FRL rate is valid
  drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC
  drm/i915/hdmi: Add helper to write FRL CFG register
  drm/i915/hdmi_frl_dfm: Add helpers to read/write FRL DFM registers
  drm/i915/hdmi_frl_dfm: Add function to compute FRL DFM config
  drm/i915/hdmi: Add FRL clock computation based on DFM
  drm/i915/hdmi: Add support for sending uevent to user for FRL training
    failure
  drm/i915/ddi: Wire FRL into the HDMI DDI enable/disable path
  drm/i915/hdmi: Add read out for FRL state
  drm/i915/display: Add FRL members to the state checker
  drm/i915/hdmi: Compute output format for HDMI FRL mode

Suraj Kandpal (7):
  drm/i915/hdmi: Introduce intel_hdmi_frl_level() for per-lane TxFFE
  drm/i915/hdmi: Drive per-lane TxFFE during FRL link training
  drm/i915/ltphy: Add PLL tables for HDMI FRL
  drm/i915/ltphy: Add safegaurd when calculation HDMI FRL state
  drm/i915/ltphy: Calculate port clock for HDMI FRL
  drm/i915/ltphy: Verify HDMI FRL tables
  drm/i915/ddi_buf: Add Vswing table for HDMI FRL

Vandita Kulkarni (9):
  drm/i915/hdmi: Parse frl max link rate from vbt
  drm/i915/hdmi: Rename port clock limit to specify tmds clock
  drm/i915/hdmi: Rename port clock valid to specify tmds clock
  drm/i915/hdmi: Add FRL port and mode clock valid
  drm/i915/hdmi_frl_dfm_regs: Define DFM registers
  drm/i915/hdmi_frl_dfm: Define frl_dfm structure
  drm/i915/hdmi_frl_dfm: Add non dsc frl capacity computation helpers
  drm/i915/hdmi_frl_dfm: Handle FRL Link M/N
  drm/i915/hdmi: Enable FRL based mode clock valid

 drivers/gpu/drm/display/drm_scdc_helper.c     | 212 +++++
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/display/intel_bios.c     |  53 ++
 drivers/gpu/drm/i915/display/intel_bios.h     |   1 +
 drivers/gpu/drm/i915/display/intel_cx0_phy.c  |  23 +
 drivers/gpu/drm/i915/display/intel_cx0_phy.h  |   1 +
 .../gpu/drm/i915/display/intel_cx0_phy_regs.h |   1 +
 drivers/gpu/drm/i915/display/intel_ddi.c      | 162 +++-
 .../drm/i915/display/intel_ddi_buf_trans.c    |  25 +
 drivers/gpu/drm/i915/display/intel_display.c  |   9 +
 .../gpu/drm/i915/display/intel_display_regs.h |  26 +
 .../drm/i915/display/intel_display_types.h    |  38 +
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 808 +++++++++++++++-
 drivers/gpu/drm/i915/display/intel_hdmi.h     |  14 +-
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 892 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h | 126 +++
 .../i915/display/intel_hdmi_frl_dfm_regs.h    |  36 +
 drivers/gpu/drm/i915/display/intel_lt_phy.c   | 315 ++++++-
 drivers/gpu/drm/i915/display/intel_lt_phy.h   |   1 +
 drivers/gpu/drm/i915/display/intel_vbt_defs.h |   7 +
 drivers/gpu/drm/xe/Makefile                   |   1 +
 include/drm/display/drm_scdc.h                |  26 +
 include/drm/display/drm_scdc_helper.h         |  22 +
 23 files changed, 2704 insertions(+), 96 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm_regs.h

-- 
2.50.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
@ 2026-08-07  4:13 ` 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
                   ` (43 subsequent siblings)
  44 siblings, 2 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Parse the maximum FRL link rate from VBT and store it for use
during FRL mode selection and link training.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_bios.c     | 53 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_bios.h     |  1 +
 drivers/gpu/drm/i915/display/intel_vbt_defs.h |  7 +++
 3 files changed, 61 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 97cbae2e547e..6354fa4041dc 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2734,6 +2734,43 @@ static bool is_port_valid(struct intel_display *display, enum port port)
 	return true;
 }
 
+static int _intel_bios_hdmi_max_frl_rate(const struct intel_bios_encoder_data *devdata)
+{
+	struct intel_display *display = devdata->display;
+
+	if (display->vbt.version >= 237 &&
+	    devdata->child.hdmi_max_frl_rate_valid) {
+		switch (devdata->child.hdmi_max_frl_rate) {
+		default:
+		case HDMI_MAX_FRL_RATE_PLATFORM:
+			drm_dbg_kms(display->drm,
+				    "HDMI limited to support only TMDS modes\n");
+			return 0;
+		case HDMI_MAX_FRL_RATE_3G:
+			return 3000000;
+		case HDMI_MAX_FRL_RATE_6G:
+			return 6000000;
+		case HDMI_MAX_FRL_RATE_8G:
+			return 8000000;
+		case HDMI_MAX_FRL_RATE_10G:
+			return 10000000;
+		case HDMI_MAX_FRL_RATE_12G:
+			return 12000000;
+		}
+	}
+
+	/*
+	 * When hdmi_max_frl_rate_valid is 0
+	 * Don't consider the hdmi_max_frl_rate for
+	 * limiting the FRL Rates on FRL-capable displays
+	 */
+	if (display->vbt.version >= 237 &&
+	    display->platform.meteorlake)
+		return 12000000;
+
+	return 0;
+}
+
 static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 {
 	struct intel_display *display = devdata->display;
@@ -2741,6 +2778,7 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 	bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
 	int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
 	enum port port;
+	int hdmi_max_frl_rate;
 
 	port = intel_bios_encoder_port(devdata);
 	if (port == PORT_NONE)
@@ -2806,6 +2844,12 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 			    "Port %c VBT DP max link rate: %d\n",
 			    port_name(port), dp_max_link_rate);
 
+	hdmi_max_frl_rate = _intel_bios_hdmi_max_frl_rate(devdata);
+	if (hdmi_max_frl_rate)
+		drm_dbg_kms(display->drm,
+			    "VBT HDMI max frl rate for port %c: %d\n",
+			    port_name(port), hdmi_max_frl_rate);
+
 	/*
 	 * FIXME need to implement support for VBT
 	 * vswing/preemph tables should this ever trigger.
@@ -3879,3 +3923,12 @@ void intel_bios_debugfs_register(struct intel_display *display)
 	debugfs_create_file("i915_vbt", 0444, display->drm->debugfs_root,
 			    display, &intel_bios_vbt_fops);
 }
+
+int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	const struct intel_bios_encoder_data *devdata;
+
+	devdata = intel_bios_encoder_data_lookup(display, encoder->port);
+	return _intel_bios_hdmi_max_frl_rate(devdata);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 75dff27b4228..53d46c9fa6e1 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -102,6 +102,7 @@ int intel_bios_hdmi_max_tmds_clock(const struct intel_bios_encoder_data *devdata
 void intel_bios_for_each_encoder(struct intel_display *display,
 				 void (*func)(struct intel_display *display,
 					      const struct intel_bios_encoder_data *devdata));
+int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder);
 
 void intel_bios_debugfs_register(struct intel_display *display);
 
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index 0dc13d080e8a..db7484542dc0 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -381,6 +381,13 @@ struct bdb_general_features {
 #define HDMI_MAX_DATA_RATE_340		4			/* 249+ */
 #define HDMI_MAX_DATA_RATE_300		5			/* 249+ */
 
+#define HDMI_MAX_FRL_RATE_PLATFORM	0			/* 237 */
+#define HDMI_MAX_FRL_RATE_3G		1			/* 237 */
+#define HDMI_MAX_FRL_RATE_6G		2			/* 237 */
+#define HDMI_MAX_FRL_RATE_8G		3			/* 237 */
+#define HDMI_MAX_FRL_RATE_10G		4			/* 237 */
+#define HDMI_MAX_FRL_RATE_12G		5			/* 237 */
+
 #define LEGACY_CHILD_DEVICE_CONFIG_SIZE		33
 
 /* DDC Bus DDI Type 155+ */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 02/44] drm/i915/hdmi: Add new data members for FRL configuration
  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-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 03/44] drm/i915/hdmi: Add FRL link rate cap Ankit Nautiyal
                   ` (42 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

HDMI supports higher resolutions using Fixed Rate Link.
Source needs to do FRL link training on the 4 lanes before video
stream transmission.

Add the members to crtc_state and intel_hdmi for identifying the FRL
supporting HDMI sink and to maintain the FRL training information after
successful training.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  9 +++++
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 36 +++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 20a07ea06b5e..76fa6debb852 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1687,8 +1687,17 @@ struct intel_hdmi {
 		enum drm_dp_dual_mode_type type;
 		int max_tmds_clock;
 	} dp_dual_mode;
+	bool has_sink_hdmi_21;
+	int max_frl_rate;
+	int max_dsc_frl_rate;
 	struct intel_connector *attached_connector;
 	struct cec_notifier *cec_notifier;
+	struct {
+		bool trained;
+		int lanes;
+		int rate_gbps;
+		int ffe_level;
+	} frl;
 };
 
 struct intel_dp_mst_encoder;
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 9b637e38a1a5..65d91fc9f9ce 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2485,6 +2485,8 @@ intel_hdmi_unset_edid(struct drm_connector *_connector)
 	struct intel_connector *connector = to_intel_connector(_connector);
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 
+	intel_hdmi->has_sink_hdmi_21 = false;
+
 	intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
 	intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
 
@@ -2545,6 +2547,38 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *_connector)
 	}
 }
 
+static void
+intel_hdmi_reset_frl_config(struct intel_hdmi *intel_hdmi)
+{
+	intel_hdmi->frl.trained = false;
+	intel_hdmi->frl.lanes = 0;
+	intel_hdmi->frl.rate_gbps = 0;
+	intel_hdmi->frl.ffe_level = 0;
+}
+
+static void
+intel_hdmi_init_frl_config(struct intel_connector *connector)
+{
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
+	int max_src_frl_rate =
+		DIV_ROUND_UP(intel_bios_hdmi_max_frl_rate(encoder), 1000000) * 4;
+	int max_sink_dsc_frl_rate =
+		intel_hdmi_sink_dsc_max_frl_rate(&connector->base);
+	int max_sink_frl_rate =
+		intel_hdmi_sink_max_frl_rate(&connector->base);
+
+	intel_hdmi->has_sink_hdmi_21 = max_sink_frl_rate > 0;
+
+	intel_hdmi->max_frl_rate = min(max_sink_frl_rate,
+				       max_src_frl_rate);
+
+	intel_hdmi->max_dsc_frl_rate = min(max_sink_dsc_frl_rate,
+					   max_src_frl_rate);
+
+	intel_hdmi_reset_frl_config(intel_hdmi);
+}
+
 static bool
 intel_hdmi_set_edid(struct drm_connector *_connector)
 {
@@ -2576,6 +2610,8 @@ intel_hdmi_set_edid(struct drm_connector *_connector)
 	if (drm_edid_is_digital(drm_edid)) {
 		intel_hdmi_dp_dual_mode_detect(&connector->base);
 
+		intel_hdmi_init_frl_config(connector);
+
 		connected = true;
 	}
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 03/44] drm/i915/hdmi: Add FRL link rate cap
  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-08-07  4:13 ` [PATCH 02/44] drm/i915/hdmi: Add new data members for FRL configuration Ankit Nautiyal
@ 2026-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 04/44] drm/drm_scdc_helper: Add SCDC helper funcs for FRL Ankit Nautiyal
                   ` (41 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add a member rate_cap to store the highest FRL rate the link is believed
to sustain. This is initially set based on the source and sink FRL
capabilities, and updated only when the capabilities change. To achieve
this, the reset is gated by a reset_rate_cap flag, so that rate_cap is
left as is on a plain re-probe.

Also reset the rate cap when the status changes to disconnected, so that
a re-plug of the same sink starts again from the full capability.

Later during a Link training failure at a specific rate, rate_cap can be
lowered, and since it is retained across a re-probe, the next training
attempt will honor the reduced cap. No user for now, this will be used
in the later changes.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  2 ++
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 33 ++++++++++++++++---
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 76fa6debb852..ba51de6c4e57 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1697,6 +1697,8 @@ struct intel_hdmi {
 		int lanes;
 		int rate_gbps;
 		int ffe_level;
+		int rate_cap;
+		bool reset_rate_cap;
 	} frl;
 };
 
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 65d91fc9f9ce..18d4e79ac54c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2567,14 +2567,30 @@ intel_hdmi_init_frl_config(struct intel_connector *connector)
 		intel_hdmi_sink_dsc_max_frl_rate(&connector->base);
 	int max_sink_frl_rate =
 		intel_hdmi_sink_max_frl_rate(&connector->base);
+	int max_frl_rate, max_dsc_frl_rate;
 
 	intel_hdmi->has_sink_hdmi_21 = max_sink_frl_rate > 0;
 
-	intel_hdmi->max_frl_rate = min(max_sink_frl_rate,
-				       max_src_frl_rate);
+	max_frl_rate = min(max_sink_frl_rate, max_src_frl_rate);
 
-	intel_hdmi->max_dsc_frl_rate = min(max_sink_dsc_frl_rate,
-					   max_src_frl_rate);
+	max_dsc_frl_rate = min(max_sink_dsc_frl_rate,
+			       max_src_frl_rate);
+	/*
+	 * Set the FRL rate cap on connect / capability change only.
+	 * Leaving it untouched on a plain re-probe lets a future
+	 * training-driven reduction persist across the retry.
+	 */
+	if (max_frl_rate != intel_hdmi->max_frl_rate ||
+	    max_dsc_frl_rate != intel_hdmi->max_dsc_frl_rate)
+		intel_hdmi->frl.reset_rate_cap = true;
+
+	intel_hdmi->max_frl_rate = max_frl_rate;
+	intel_hdmi->max_dsc_frl_rate = max_dsc_frl_rate;
+
+	if (intel_hdmi->frl.reset_rate_cap) {
+		intel_hdmi->frl.rate_cap = max(max_frl_rate, max_dsc_frl_rate);
+		intel_hdmi->frl.reset_rate_cap = false;
+	}
 
 	intel_hdmi_reset_frl_config(intel_hdmi);
 }
@@ -2656,9 +2672,16 @@ intel_hdmi_detect(struct drm_connector *_connector, bool force)
 out:
 	intel_display_power_put(display, POWER_DOMAIN_GMBUS, wakeref);
 
-	if (status != connector_status_connected)
+	if (status != connector_status_connected) {
 		cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier);
 
+		/*
+		 * Reset the rate cap so that the next connect re-initializes
+		 * frl.rate_cap to the capability ceiling.
+		 */
+		intel_hdmi->frl.reset_rate_cap = true;
+	}
+
 	return status;
 }
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 04/44] drm/drm_scdc_helper: Add SCDC helper funcs for FRL
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (2 preceding siblings ...)
  2026-08-07  4:13 ` [PATCH 03/44] drm/i915/hdmi: Add FRL link rate cap Ankit Nautiyal
@ 2026-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 05/44] drm/i915/display: Add registers for HDMI FRL configuration Ankit Nautiyal
                   ` (40 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

FRL (Fixed Rate Link) uses a set of SCDC registers to configure and
monitor link training between the source and sink.

Add the register definitions and helper functions to read and
configure these SCDC registers for FRL link training.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/display/drm_scdc_helper.c | 212 ++++++++++++++++++++++
 include/drm/display/drm_scdc.h            |  26 +++
 include/drm/display/drm_scdc_helper.h     |  22 +++
 3 files changed, 260 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index df878aad4a36..8a074f674051 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -276,3 +276,215 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
 	return true;
 }
 EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+/**
+ * drm_scdc_read_update_flags - read the SCDC update flags
+ * @adapter: I2C adapter for DDC channel
+ *
+ * Returns:
+ * 8bit SCDC update
+ */
+u8 drm_scdc_read_update_flags(struct i2c_adapter *adapter)
+{
+	u8 update = 0;
+	int ret;
+
+	ret = drm_scdc_readb(adapter, SCDC_UPDATE_0, &update);
+	if (ret < 0)
+		DRM_DEBUG_KMS("Failed to read scdc update: %d\n", ret);
+
+	return update;
+}
+EXPORT_SYMBOL(drm_scdc_read_update_flags);
+
+/**
+ * drm_scdc_clear_update_flags - Clears the given update flag bits by writing 1
+ * @adapter: I2C adapter for DDC channel
+ * @update_flags: update flag bits to be cleared
+ *
+ * Returns:
+ * 0 on success, negative error code otherwise.
+ */
+int drm_scdc_clear_update_flags(struct i2c_adapter *adapter, u8 update_flags)
+{
+	int ret;
+
+	/* Read Request Test is the only update flag the source cannot clear */
+	if (update_flags & SCDC_READ_REQUEST_TEST) {
+		DRM_DEBUG_KMS("SCDC Update flag/s 0x%x cannot be cleared\n",
+			      update_flags);
+		return -EINVAL;
+	}
+
+	ret = drm_scdc_writeb(adapter, SCDC_UPDATE_0, update_flags);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("Failed to clear SCDC Update flag/s\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_scdc_clear_update_flags);
+
+/**
+ * drm_scdc_read_status_flags - Read the status flags from offset 0x40
+ * @adapter: I2C adapter for DDC channel
+ *
+ * Returns:
+ * 8 bit value read from the offset 0x40
+ */
+u8 drm_scdc_read_status_flags(struct i2c_adapter *adapter)
+{
+	u8 update = 0;
+	int ret;
+
+	ret = drm_scdc_readb(adapter, SCDC_STATUS_FLAGS_0, &update);
+	if (ret < 0)
+		DRM_DEBUG_KMS("Failed to read scdc status flag: %d\n", ret);
+
+	return update;
+}
+EXPORT_SYMBOL(drm_scdc_read_status_flags);
+
+/**
+ * drm_scdc_config_frl - configure the sink for starting FRL training
+ * @adapter: I2C adapter for DDC channel
+ * @frl_rate: FRL rate per lane in Gbps (3, 6, 8, 10, 12, 16, 20 or 24).
+ * @num_lanes: no. of lanes required, can be either 3 or 4.
+ * @ffe_levels: max TxFFE level supported for the given FRL rate;
+ *              0-3 for rates up to 12 Gbps, 0-7 for 16/20/24 Gbps.
+ *              A prohibited value is clamped to 0 (per spec).
+ *
+ * Returns:
+ * 0 if the SCDC offsets for FRL training are successfully configured,
+ * negative error code otherwise.
+ */
+int drm_scdc_config_frl(struct i2c_adapter *adapter, int frl_rate,
+			int num_lanes, int ffe_levels)
+{
+	u8 write_buf = 0;
+	int ret;
+
+	if (num_lanes > 4 || num_lanes < 3) {
+		DRM_DEBUG_KMS("No. of lanes can be 3 or 4 only\n");
+		return -EINVAL;
+	}
+	if (ffe_levels > 7 || (frl_rate < 16 && ffe_levels > 3)) {
+		DRM_DEBUG_KMS("Prohibited Max FFE level %d, defaulting to Max FFE level 0\n",
+			      ffe_levels);
+		ffe_levels = 0;
+	}
+
+	switch (frl_rate) {
+	case 3:
+		write_buf |= (num_lanes == 3) ? SCDC_FRL_RATE_3GBPS_3LANES : 0;
+		break;
+	case 6:
+		write_buf |= (num_lanes == 3) ? SCDC_FRL_RATE_6GBPS_3LANES :
+			     SCDC_FRL_RATE_6GBPS_4LANES;
+		break;
+	case 8:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_8GBPS_4LANES : 0;
+		break;
+	case 10:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_10GBPS_4LANES : 0;
+		break;
+	case 12:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_12GBPS_4LANES : 0;
+		break;
+	case 16:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_16GBPS_4LANES : 0;
+		break;
+	case 20:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_20GBPS_4LANES : 0;
+		break;
+	case 24:
+		write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_24GBPS_4LANES : 0;
+		break;
+	default:
+		DRM_DEBUG_KMS("Invalid FRL rate =%dGbps\n", frl_rate);
+		return -EINVAL;
+	}
+
+	if (!write_buf) {
+		DRM_DEBUG_KMS("Invalid FRL rate and lane combination\n");
+		return -EINVAL;
+	}
+
+	write_buf |= (ffe_levels << SCDC_FFE_LEVELS_SHIFT);
+
+	ret = drm_scdc_writeb(adapter, SCDC_CONFIG_1, write_buf);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("Failed to write SCDC config: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_scdc_config_frl);
+
+/**
+ * drm_scdc_disable_frl - Clear FRL Rate indicating TMDS
+ * @adapter: I2C adapter for DDC channel
+ *
+ * Returns:
+ * 0 if the FRL Rate is successfully reset, negative error code otherwise.
+ */
+int drm_scdc_disable_frl(struct i2c_adapter *adapter)
+{
+	u8 buf = 0;
+	int ret;
+
+	ret = drm_scdc_readb(adapter, SCDC_CONFIG_1, &buf);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("Failed to read SCDC_CONFIG_1\n");
+		return ret;
+	}
+
+	buf &= ~SCDC_FRL_RATE_MASK;
+
+	ret = drm_scdc_writeb(adapter, SCDC_CONFIG_1, buf);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("Failed to reset FRL rate\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_scdc_disable_frl);
+
+/**
+ * drm_scdc_get_ltp - get the Link training patterns for the 4 lanes
+ * @adapter: I2C adapter for DDC channel
+ * @ltp: pointer array for reading Link training patterns for the 4 lanes.
+ *
+ * Returns:
+ * 0 on success also filling ltp out argument, negative error code otherwise.
+ */
+int drm_scdc_get_ltp(struct i2c_adapter *adapter,
+		     enum drm_scdc_frl_ltp ltp[4])
+{
+	u8 buf;
+	int ret;
+
+	ret = drm_scdc_readb(adapter, SCDC_STATUS_FLAGS_1, &buf);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("failed to read link training pattern for lanes 0/1 ret = %d\n", ret);
+		return ret;
+	}
+
+	ltp[0] = buf & SCDC_LN_0_2_LTP_MASK;
+	ltp[1] = (buf & SCDC_LN_1_3_LTP_MASK) >> 4;
+
+	ret = drm_scdc_readb(adapter, SCDC_STATUS_FLAGS_2, &buf);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("failed to read link training pattern for lanes 2/3 ret = %d\n", ret);
+		return ret;
+	}
+
+	ltp[2] = buf & SCDC_LN_0_2_LTP_MASK;
+	ltp[3] = (buf & SCDC_LN_1_3_LTP_MASK) >> 4;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_scdc_get_ltp);
diff --git a/include/drm/display/drm_scdc.h b/include/drm/display/drm_scdc.h
index 3d58f37e8ed8..7f8845ff6e72 100644
--- a/include/drm/display/drm_scdc.h
+++ b/include/drm/display/drm_scdc.h
@@ -29,6 +29,11 @@
 #define SCDC_SOURCE_VERSION 0x02
 
 #define SCDC_UPDATE_0 0x10
+#define  SCDC_LIP_UPDATE (1 << 7)
+#define  SCDC_RSED_UPDATE (1 << 6)
+#define  SCDC_FLT_UPDATE (1 << 5)
+#define  SCDC_FRL_START (1 << 4)
+#define  SCDC_SOURCE_TEST_UPDATE (1 << 3)
 #define  SCDC_READ_REQUEST_TEST (1 << 2)
 #define  SCDC_CED_UPDATE (1 << 1)
 #define  SCDC_STATUS_UPDATE (1 << 0)
@@ -46,7 +51,24 @@
 #define SCDC_CONFIG_0 0x30
 #define  SCDC_READ_REQUEST_ENABLE (1 << 0)
 
+#define SCDC_CONFIG_1 0x31
+#define  SCDC_FRL_RATE_MASK		0xF
+#define  SCDC_FRL_DISABLE		0
+#define  SCDC_FRL_RATE_3GBPS_3LANES	1
+#define  SCDC_FRL_RATE_6GBPS_3LANES	2
+#define  SCDC_FRL_RATE_6GBPS_4LANES	3
+#define  SCDC_FRL_RATE_8GBPS_4LANES	4
+#define  SCDC_FRL_RATE_10GBPS_4LANES	5
+#define  SCDC_FRL_RATE_12GBPS_4LANES	6
+#define  SCDC_FRL_RATE_16GBPS_4LANES	7
+#define  SCDC_FRL_RATE_20GBPS_4LANES	8
+#define  SCDC_FRL_RATE_24GBPS_4LANES	9
+#define  SCDC_FFE_LEVELS_SHIFT		4
+
 #define SCDC_STATUS_FLAGS_0 0x40
+#define  SCDC_DSC_DECODE_FAIL (1 << 7)
+#define  SCDC_FLT_READY (1 << 6)
+#define  SCDC_LANE3_LOCKED (1 << 4)
 #define  SCDC_CH2_LOCK (1 << 3)
 #define  SCDC_CH1_LOCK (1 << 2)
 #define  SCDC_CH0_LOCK (1 << 1)
@@ -55,6 +77,10 @@
 
 #define SCDC_STATUS_FLAGS_1 0x41
 
+#define SCDC_STATUS_FLAGS_2 0x42
+#define  SCDC_LN_0_2_LTP_MASK 0xF
+#define  SCDC_LN_1_3_LTP_MASK (0xF << 4)
+
 #define SCDC_ERR_DET_0_L 0x50
 #define SCDC_ERR_DET_0_H 0x51
 #define SCDC_ERR_DET_1_L 0x52
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..0075bfd2e19d 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -36,6 +36,20 @@ ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
 ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
 		       const void *buffer, size_t size);
 
+enum drm_scdc_frl_ltp {
+	SCDC_FRL_NO_LTP = 0,
+	SCDC_FRL_LTP1,
+	SCDC_FRL_LTP2,
+	SCDC_FRL_LTP3,
+	SCDC_FRL_LTP4,
+	SCDC_FRL_LTP5,
+	SCDC_FRL_LTP6,
+	SCDC_FRL_LTP7,
+	SCDC_FRL_LTP8,
+	SCDC_FRL_CHNG_FFE = 0xE,
+	SCDC_FRL_CHNG_RATE = 0xF,
+};
+
 /**
  * drm_scdc_readb - read a single byte from SCDC
  * @adapter: I2C adapter
@@ -76,5 +90,13 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
 
 bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
 bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
+u8 drm_scdc_read_update_flags(struct i2c_adapter *adapter);
+int drm_scdc_clear_update_flags(struct i2c_adapter *adapter, u8 update_flags);
+u8 drm_scdc_read_status_flags(struct i2c_adapter *adapter);
+int drm_scdc_config_frl(struct i2c_adapter *adapter, int frl_rate,
+			int num_lanes, int ffe_levels);
+int drm_scdc_disable_frl(struct i2c_adapter *adapter);
+int drm_scdc_get_ltp(struct i2c_adapter *adapter,
+		     enum drm_scdc_frl_ltp ltp[4]);
 
 #endif
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 05/44] drm/i915/display: Add registers for HDMI FRL configuration
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (3 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 06/44] drm/i915/display: Add new members in crtc_state for " Ankit Nautiyal
                   ` (39 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add registers for HDMI FRL configuration and link training.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../gpu/drm/i915/display/intel_display_regs.h | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 0f5018482497..d05827dd1236 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -550,6 +550,32 @@
 #define _TRANS_MULT_B		0x6102c
 #define TRANS_MULT(dev_priv, trans)	_MMIO_TRANS2(dev_priv, (trans), _TRANS_MULT_A)
 
+/* HDMI FRL Configuration */
+#define _TRANS_HDMI_FRL_CFG_A				0x600b0
+#define TRANS_HDMI_FRL_CFG(dev_priv, trans)		_MMIO_TRANS2(dev_priv, \
+								     (trans), \
+								     _TRANS_HDMI_FRL_CFG_A)
+#define  TRANS_HDMI_FRL_ENABLE				REG_BIT(31)
+#define  TRANS_HDMI_TMDS_ENABLE				0
+#define  TRANS_HDMI_FRL_TRAINING_COMPLETE		REG_BIT(28)
+#define  TRANS_HDMI_DISABLE_DFM_MASKING			REG_BIT(20)
+#define  TRANS_HDMI_R_B_SCHED_ENABLE_MASK		REG_BIT(19)
+#define  TRANS_HDMI_R_B_SCHED_ENABLE(val)		REG_FIELD_PREP(TRANS_HDMI_R_B_SCHED_ENABLE_MASK, val)
+#define  TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH_MASK		REG_GENMASK(18, 16)
+#define  TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH(val)		REG_FIELD_PREP(TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH_MASK, val)
+#define  TRANS_HDMI_MIN_BLANK_CHAR_MASK			REG_GENMASK(15, 12)
+#define  TRANS_HDMI_MIN_BLANK_CHAR(val)			REG_FIELD_PREP(TRANS_HDMI_MIN_BLANK_CHAR_MASK, val)
+#define  TRANS_HDMI_MIN_BLANK_CHAR_VAL			0xa
+#define  TRANS_HDMI_FRL_PKT_PAYLOAD_MAX_MASK		REG_GENMASK(9, 0)
+#define  TRANS_HDMI_FRL_PKT_PAYLOAD_MAX(val)		REG_FIELD_PREP(TRANS_HDMI_FRL_PKT_PAYLOAD_MAX_MASK, val)
+#define  TRANS_HDMI_PAYLOAD_UPPER_BOUND			0x3fe
+
+#define _TRANS_HDMI_FRL_TRAIN_A				0x600b4
+#define TRANS_HDMI_FRL_TRAIN(dev_priv, trans)		_MMIO_TRANS2(dev_priv, \
+								     (trans), \
+								     _TRANS_HDMI_FRL_TRAIN_A)
+#define  TRANS_HDMI_FRL_LTP(pattern, lane) ((pattern) << (lane) * 8)
+
 /* Hotplug control (945+ only) */
 #define PORT_HOTPLUG_EN(dev_priv)		_MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61110)
 #define   PORTB_HOTPLUG_INT_EN			(1 << 29)
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 06/44] drm/i915/display: Add new members in crtc_state for FRL configuration
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (4 preceding siblings ...)
  2026-08-07  4:13 ` [PATCH 05/44] drm/i915/display: Add registers for HDMI FRL configuration Ankit Nautiyal
@ 2026-08-07  4:13 ` 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
                   ` (38 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add new struture to store FRL related configurations for a pipe.
These members to be calculated during compute config phase, when FRL
mode is to be used.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../drm/i915/display/intel_display_types.h    | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index ba51de6c4e57..00775ad9019c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1445,6 +1445,32 @@ struct intel_crtc_state {
 
 	/* to track changes in plane color blocks */
 	bool plane_color_changed;
+
+	struct {
+		/* Go for FRL training */
+		bool enable;
+
+		/* Enable resource based scheduling */
+		bool rsrc_sched_en;
+
+		/* can be either 3 or 4 lanes */
+		u8 required_lanes;
+
+		/* required rate - can be 3, 6, 8, 10, 12 Gbps */
+		u8 required_rate;
+
+		/* FRL DFM Parameters */
+		u32 tb_borrowed, tb_actual, tb_threshold_min, active_char_buf_threshold;
+
+		/* FRL DFM DSC Tribytes */
+		u32 hcactive_tb, hctotal_tb;
+
+		/* Clock parameters in KHz */
+		u32 div18;
+
+		/* link m/n */
+		u32 link_m, link_n;
+	} frl;
 };
 
 enum intel_pipe_crc_source {
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 07/44] drm/i915/intel_cx0_phy_regs: Add HDMI FRL SHIFT EN bit in PORT_BUF_CTL_1
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (5 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 08/44] drm/i915/ddi: Update Transcoder/DDI registers with the frl bits Ankit Nautiyal
                   ` (37 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add HDMI_FRL_SHFTR_EN bit in PORT_BUF_CTL_1.
This bit enables the HDMI FRL 18b to 20b shifting and data output.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
index 152a4e751bdc..64fdf84b98ab 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
@@ -112,6 +112,7 @@
 #define   XELPDP_TCSS_POWER_REQUEST			REG_BIT(5)
 #define   XELPDP_TCSS_POWER_STATE			REG_BIT(4)
 #define   XELPDP_PORT_WIDTH_MASK			REG_GENMASK(3, 1)
+#define   XELPDP_PORT_HDMI_FRL_SHFTR_EN			REG_BIT(0)
 #define   XELPDP_PORT_WIDTH(width)			REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, \
 								       ((width) == 3 ? 4 : (width) - 1))
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 08/44] drm/i915/ddi: Update Transcoder/DDI registers with the frl bits
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (6 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 09/44] drm/i915/hdmi: Enable Scrambling only for TMDS mode Ankit Nautiyal
                   ` (36 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

For platforms supporting HDMI FRL we need to fill the lane count
in Transcoder and DDI/PORT registers for FRL mode.
Similarly, FRL SHIFTER ENABLE, and DATA_WIDTH bits are to be set
in FRL mode. These bits are written in both the DDI_BUF_CTL and
PORT_BUF_CTL registers.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 25 +++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index bf5788c5bbd3..48411a4d30c3 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3099,12 +3099,20 @@ static void intel_ddi_buf_disable(struct intel_encoder *encoder,
 {
 	struct intel_display *display = to_intel_display(encoder);
 	enum port port = encoder->port;
+	u32 val;
 
 	intel_de_rmw(display, DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE, 0);
 
 	if (DISPLAY_VER(display) >= 14)
 		intel_wait_ddi_buf_idle(display, port);
 
+	/* Clear PORT_BUF_CTL HDMI FRL Shifter Enable to 0 */
+	if (crtc_state->frl.enable) {
+		val = intel_de_read(display, XELPDP_PORT_BUF_CTL1(display, port));
+		intel_de_write(display, XELPDP_PORT_BUF_CTL1(display, port),
+			       val & ~XELPDP_PORT_HDMI_FRL_SHFTR_EN);
+	}
+
 	mtl_ddi_disable_d2d(encoder);
 
 	if (intel_crtc_has_dp_encoder(crtc_state)) {
@@ -3473,8 +3481,9 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 	 * On ADL_P the PHY link rate and lane count must be programmed but
 	 * these are both 0 for HDMI.
 	 *
-	 * But MTL onwards HDMI2.1 is supported and in TMDS mode this
-	 * is filled with lane count, already set in the crtc_state.
+	 * But MTL onwards HDMI FRL is supported and in FRL mode, port width
+	 * needs to be filled with either 3 or 4 lanes. For TMDS mode this
+	 * is always filled with 4 lanes, already set in the crtc_state.
 	 * The same is required to be filled in PORT_BUF_CTL for C10/20 Phy.
 	 */
 	if (dig_port->lane_reversal)
@@ -3490,8 +3499,18 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 		if (dig_port->lane_reversal)
 			port_buf |= XELPDP_PORT_REVERSAL;
 
+		if (crtc_state->frl.enable) {
+			port_buf |= XELPDP_PORT_HDMI_FRL_SHFTR_EN;
+			port_buf |= XELPDP_PORT_BUF_PORT_DATA_20BIT;
+			buf_ctl |= DDI_BUF_PORT_DATA_20BIT;
+		} else {
+			buf_ctl &= ~DDI_BUF_PORT_DATA_MASK;
+		}
+
 		intel_de_rmw(display, XELPDP_PORT_BUF_CTL1(display, port),
-			     XELPDP_PORT_WIDTH_MASK | XELPDP_PORT_REVERSAL, port_buf);
+			     XELPDP_PORT_WIDTH_MASK | XELPDP_PORT_REVERSAL |
+			     XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK |
+			     XELPDP_PORT_HDMI_FRL_SHFTR_EN, port_buf);
 
 		buf_ctl |= DDI_PORT_WIDTH(crtc_state->lane_count);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 09/44] drm/i915/hdmi: Enable Scrambling only for TMDS mode
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (7 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 10/44] drm/i915/ddi: Simplify intel_ddi_enable() Ankit Nautiyal
                   ` (35 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Enable scrambling in SCDC only for TMDS mode. For FRL mode scrambling
is handled as part of the FRL protocol and should not be configured
via the TMDS scrambling path.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 18d4e79ac54c..b0534fba4e5f 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2430,7 +2430,8 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
 
 	pipe_config->lane_count = 4;
 
-	if (scdc->scrambling.supported && source_supports_scrambling(encoder)) {
+	if (scdc->scrambling.supported && source_supports_scrambling(encoder) &&
+	    !pipe_config->frl.enable) {
 		if (scdc->scrambling.low_rates)
 			pipe_config->hdmi_scrambling = true;
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 10/44] drm/i915/ddi: Simplify intel_ddi_enable()
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (8 preceding siblings ...)
  2026-08-07  4:13 ` [PATCH 09/44] drm/i915/hdmi: Enable Scrambling only for TMDS mode Ankit Nautiyal
@ 2026-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 11/44] drm/i915/ddi: Factor out common transcoder/vblank enable sequence Ankit Nautiyal
                   ` (34 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Currently, intel_ddi_enable() has more HDMI- and DP-specific steps
than shared ones. Furthermore, from MTL onwards the sequence of
enabling the Port and TRANS_CONF has also diverged, which is not
currently accounted for.

Move the encoder-specific steps into their respective helpers and
simplify intel_ddi_enable(), which now simply dispatches to
intel_ddi_enable_{hdmi,dp}() and calls intel_hdcp_enable() at the
end.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 102 +++++++++++++----------
 1 file changed, 56 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 48411a4d30c3..4f089df82ec8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3376,8 +3376,47 @@ static void intel_ddi_enable_dp(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+	struct intel_crtc *pipe_crtc;
+	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 	enum port port = encoder->port;
 
+	/* 128b/132b SST */
+	if (intel_dp_is_uhbr(crtc_state)) {
+		const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+		u64 crtc_clock_hz = KHz(adjusted_mode->crtc_clock);
+
+		intel_de_write(display, TRANS_DP2_VFREQHIGH(cpu_transcoder),
+			       TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz >> 24));
+		intel_de_write(display, TRANS_DP2_VFREQLOW(cpu_transcoder),
+			       TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz & 0xffffff));
+	}
+
+	intel_ddi_enable_transcoder_func(encoder, crtc_state);
+
+	intel_vrr_transcoder_enable(crtc_state);
+
+	/* 128b/132b SST */
+	if (intel_dp_is_uhbr(crtc_state)) {
+		intel_ddi_clear_act_sent(encoder, crtc_state);
+
+		intel_de_rmw(display, TRANS_DDI_FUNC_CTL(display, cpu_transcoder), 0,
+			     TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
+
+		intel_ddi_wait_for_act_sent(encoder, crtc_state);
+		drm_dp_dpcd_poll_act_handled(&intel_dp->aux, 0);
+	}
+
+	intel_enable_transcoder(crtc_state);
+
+	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
+
+	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
+		const struct intel_crtc_state *pipe_crtc_state =
+			intel_atomic_get_new_crtc_state(state, pipe_crtc);
+
+		intel_crtc_vblank_on(pipe_crtc_state);
+	}
+
 	if (port == PORT_A && DISPLAY_VER(display) < 9)
 		intel_dp_stop_link_train(intel_dp, crtc_state);
 
@@ -3419,9 +3458,25 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 	struct drm_connector *connector = conn_state->connector;
+	struct intel_crtc *pipe_crtc;
 	enum port port = encoder->port;
 	u32 buf_ctl = 0;
 
+	intel_ddi_enable_transcoder_func(encoder, crtc_state);
+
+	intel_vrr_transcoder_enable(crtc_state);
+
+	intel_enable_transcoder(crtc_state);
+
+	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
+
+	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
+		const struct intel_crtc_state *pipe_crtc_state =
+			intel_atomic_get_new_crtc_state(state, pipe_crtc);
+
+		intel_crtc_vblank_on(pipe_crtc_state);
+	}
+
 	if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
 					       crtc_state->hdmi_high_tmds_clock_ratio,
 					       crtc_state->hdmi_scrambling))
@@ -3531,57 +3586,12 @@ static void intel_ddi_enable(struct intel_atomic_state *state,
 			     const struct intel_crtc_state *crtc_state,
 			     const struct drm_connector_state *conn_state)
 {
-	struct intel_display *display = to_intel_display(encoder);
-	struct intel_crtc *pipe_crtc;
-	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-	bool is_hdmi = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI);
-
-	/* 128b/132b SST */
-	if (!is_hdmi && intel_dp_is_uhbr(crtc_state)) {
-		const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
-		u64 crtc_clock_hz = KHz(adjusted_mode->crtc_clock);
-
-		intel_de_write(display, TRANS_DP2_VFREQHIGH(cpu_transcoder),
-			       TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz >> 24));
-		intel_de_write(display, TRANS_DP2_VFREQLOW(cpu_transcoder),
-			       TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz & 0xffffff));
-	}
-
-	intel_ddi_enable_transcoder_func(encoder, crtc_state);
-
-	intel_vrr_transcoder_enable(crtc_state);
-
-	/* 128b/132b SST */
-	if (!is_hdmi && intel_dp_is_uhbr(crtc_state)) {
-		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-		intel_ddi_clear_act_sent(encoder, crtc_state);
-
-		intel_de_rmw(display, TRANS_DDI_FUNC_CTL(display, cpu_transcoder), 0,
-			     TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
-
-		intel_ddi_wait_for_act_sent(encoder, crtc_state);
-		drm_dp_dpcd_poll_act_handled(&intel_dp->aux, 0);
-	}
-
-	intel_enable_transcoder(crtc_state);
-
-	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
-
-	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
-		const struct intel_crtc_state *pipe_crtc_state =
-			intel_atomic_get_new_crtc_state(state, pipe_crtc);
-
-		intel_crtc_vblank_on(pipe_crtc_state);
-	}
-
-	if (is_hdmi)
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
 		intel_ddi_enable_hdmi(state, encoder, crtc_state, conn_state);
 	else
 		intel_ddi_enable_dp(state, encoder, crtc_state, conn_state);
 
 	intel_hdcp_enable(state, encoder, crtc_state, conn_state);
-
 }
 
 static void intel_ddi_disable_dp(struct intel_atomic_state *state,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 11/44] drm/i915/ddi: Factor out common transcoder/vblank enable sequence
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (9 preceding siblings ...)
  2026-08-07  4:13 ` [PATCH 10/44] drm/i915/ddi: Simplify intel_ddi_enable() Ankit Nautiyal
@ 2026-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 12/44] drm/i915/ddi: Update HDMI modeset sequence for MTL+ Ankit Nautiyal
                   ` (33 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

intel_ddi_enable_dp() and intel_ddi_enable_hdmi() both contain an
identical sequence to enable the transcoder, wait for FEC status,
and turn on vblank for each pipe. Move this into a new helper,
intel_ddi_enable_transcoder_and_vblank(), to avoid the duplication.

No functional change.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 43 ++++++++++++------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 4f089df82ec8..5be4a7f00313 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3368,6 +3368,25 @@ static void trans_port_sync_stop_link_train(struct intel_atomic_state *state,
 				 crtc_state);
 }
 
+static void intel_ddi_enable_transcoder_and_vblank(struct intel_atomic_state *state,
+						   struct intel_encoder *encoder,
+						   const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct intel_crtc *pipe_crtc;
+
+	intel_enable_transcoder(crtc_state);
+
+	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
+
+	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
+		const struct intel_crtc_state *pipe_crtc_state =
+			intel_atomic_get_new_crtc_state(state, pipe_crtc);
+
+		intel_crtc_vblank_on(pipe_crtc_state);
+	}
+}
+
 static void intel_ddi_enable_dp(struct intel_atomic_state *state,
 				struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
@@ -3376,7 +3395,6 @@ static void intel_ddi_enable_dp(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
-	struct intel_crtc *pipe_crtc;
 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 	enum port port = encoder->port;
 
@@ -3406,16 +3424,7 @@ static void intel_ddi_enable_dp(struct intel_atomic_state *state,
 		drm_dp_dpcd_poll_act_handled(&intel_dp->aux, 0);
 	}
 
-	intel_enable_transcoder(crtc_state);
-
-	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
-
-	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
-		const struct intel_crtc_state *pipe_crtc_state =
-			intel_atomic_get_new_crtc_state(state, pipe_crtc);
-
-		intel_crtc_vblank_on(pipe_crtc_state);
-	}
+	intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
 
 	if (port == PORT_A && DISPLAY_VER(display) < 9)
 		intel_dp_stop_link_train(intel_dp, crtc_state);
@@ -3458,7 +3467,6 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 	struct drm_connector *connector = conn_state->connector;
-	struct intel_crtc *pipe_crtc;
 	enum port port = encoder->port;
 	u32 buf_ctl = 0;
 
@@ -3466,16 +3474,7 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 
 	intel_vrr_transcoder_enable(crtc_state);
 
-	intel_enable_transcoder(crtc_state);
-
-	intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
-
-	for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state) {
-		const struct intel_crtc_state *pipe_crtc_state =
-			intel_atomic_get_new_crtc_state(state, pipe_crtc);
-
-		intel_crtc_vblank_on(pipe_crtc_state);
-	}
+	intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
 
 	if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
 					       crtc_state->hdmi_high_tmds_clock_ratio,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 12/44] drm/i915/ddi: Update HDMI modeset sequence for MTL+
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (10 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 13/44] drm/i915/hdmi: Add function to prepare registers for FRL mode Ankit Nautiyal
                   ` (32 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Per BSpec, the HDMI enable sequence differs starting MTL+: the port
must be fully configured and enabled (DDI_CTL_DE) before enabling the
transcoder (TRANS_CONF), whereas pre-MTL platforms enable the
transcoder before the port (DDI_BUF_CTL).

Today the HDMI path still uses the pre-MTL ordering: when the MTL+ DDI
sequences were implemented, HDMI was left enabling the transcoder before
the port. This does not cause any visible issue with current TMDS usage,
but it needs to be corrected before FRL can be wired up.

Bspec: 49191, 54145 (pre-MTL)
Bspec: 65750, 68848 (MTL+)
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 5be4a7f00313..d6e7e7863d36 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3474,7 +3474,8 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 
 	intel_vrr_transcoder_enable(crtc_state);
 
-	intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
+	if (DISPLAY_VER(display) < 14)
+		intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
 
 	if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
 					       crtc_state->hdmi_high_tmds_clock_ratio,
@@ -3577,6 +3578,9 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 
 	intel_ddi_buf_enable(encoder, buf_ctl);
 
+	if (DISPLAY_VER(display) >= 14)
+		intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
+
 	intel_hdmi_poll_for_scrambling_enable(crtc_state, connector);
 }
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 13/44] drm/i915/hdmi: Add function to prepare registers for FRL mode
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (11 preceding siblings ...)
  2026-08-07  4:13 ` [PATCH 12/44] drm/i915/ddi: Update HDMI modeset sequence for MTL+ Ankit Nautiyal
@ 2026-08-07  4:13 ` Ankit Nautiyal
  2026-08-07  4:13 ` [PATCH 14/44] drm/i915/hdmi: Add functions for FRL training state machine Ankit Nautiyal
                   ` (31 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add intel_hdmi_prepare_for_frl_mode() to arm the FRL function and reset
the training pattern to the default LTP1 on all active lanes, before the
Link training sequence starts.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 22 ++++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_hdmi.h |  2 +-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index b0534fba4e5f..96542869740e 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3501,3 +3501,25 @@ int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector)
 
 	return max_lanes * rate_per_lane;
 }
+
+void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder trans = crtc_state->cpu_transcoder;
+	int num_lanes = crtc_state->frl.required_lanes;
+	u32 write_buf = 0;
+	int lane;
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	intel_de_rmw(display, TRANS_HDMI_FRL_CFG(display, trans),
+		     TRANS_HDMI_FRL_TRAINING_COMPLETE,
+		     TRANS_HDMI_FRL_ENABLE);
+
+	/* Reset Training Pattern to default 0x1 */
+	for (lane = 0; lane < num_lanes; lane++)
+		write_buf |= TRANS_HDMI_FRL_LTP(0x1, lane);
+
+	intel_de_write(display, TRANS_HDMI_FRL_TRAIN(display, trans), write_buf);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index c95ed37bcc0c..6283305b5274 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -63,7 +63,7 @@ int intel_hdmi_dsc_get_num_slices(const struct drm_display_mode *mode,
 				  int hdmi_max_slices, int hdmi_throughput);
 int intel_hdmi_dsc_get_slice_height(int vactive);
 bool intel_hdmi_is_frl(u32 clock);
-
+void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state);
 void hsw_write_infoframe(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state,
 			 unsigned int type,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 14/44] drm/i915/hdmi: Add functions for FRL training state machine
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (12 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 15/44] drm/i915/intel_hdmi: Add helper to disable FRL Ankit Nautiyal
                   ` (30 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:13 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add the FRL link training state machine and the helpers to drive it
with an HDMI FRL sink over SCDC: prepare for LTS:2, train the lanes in
LTS:3, complete training in LTS:P and fall back to legacy TMDS in LTS:L.

intel_hdmi_start_frl() drives these states for the requested rate and
lanes.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 258 ++++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_hdmi.h |   2 +
 2 files changed, 260 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 96542869740e..ff200d662a3f 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3523,3 +3523,261 @@ void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state)
 
 	intel_de_write(display, TRANS_HDMI_FRL_TRAIN(display, trans), write_buf);
 }
+
+static bool is_flt_ready(struct intel_encoder *encoder)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+
+	return drm_scdc_read_status_flags(adapter) & SCDC_FLT_READY;
+}
+
+static u8 get_frl_update_flags(struct intel_encoder *encoder)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+
+	return drm_scdc_read_update_flags(adapter);
+}
+
+static int clear_scdc_update_flags(struct intel_encoder *encoder, u8 flags)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+
+	return drm_scdc_clear_update_flags(adapter, flags);
+}
+
+static bool
+intel_hdmi_frl_prepare_lts2(struct intel_encoder *encoder,
+			    int frl_rate, int frl_lanes,
+			    int ffe_level)
+{
+#define TIMEOUT_FLT_READY_MS 250
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+	bool flt_ready = false;
+
+	if (!frl_rate || !frl_lanes)
+		return false;
+
+	if (read_poll_timeout(is_flt_ready, flt_ready,
+			      flt_ready, 1000,
+			      TIMEOUT_FLT_READY_MS * USEC_PER_MSEC,
+			      false, encoder)) {
+		drm_dbg_kms(display->drm,
+			    "HDMI sink not ready for FRL in %d\n",
+			    TIMEOUT_FLT_READY_MS);
+		return false;
+	}
+
+	if ((get_frl_update_flags(encoder) & SCDC_FLT_UPDATE))
+		clear_scdc_update_flags(encoder, SCDC_FLT_UPDATE);
+
+	/* #TODO: Source shall program TxFFE = 0 for all active lanes */
+
+	if (drm_scdc_config_frl(adapter, frl_rate, frl_lanes, ffe_level) < 0) {
+		drm_dbg_kms(display->drm,
+			    "Failed to write SCDC config regs for FRL\n");
+		return false;
+	}
+
+	return flt_ready;
+}
+
+enum frl_lt_status {
+	FRL_TRAINING_PASSED,
+	FRL_CHANGE_RATE,
+	FRL_TRAIN_CONTINUE,
+	FRL_TRAIN_RETRAIN,
+	FRL_TRAIN_STOP,
+};
+
+static int get_link_training_patterns(struct intel_encoder *encoder,
+				      enum drm_scdc_frl_ltp ltp[4])
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+
+	return drm_scdc_get_ltp(adapter, ltp);
+}
+
+static enum frl_lt_status
+intel_hdmi_train_lanes(struct intel_encoder *encoder,
+		       const struct intel_crtc_state *crtc_state,
+		       int ffe_level)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	enum transcoder trans = crtc_state->cpu_transcoder;
+	int num_lanes = crtc_state->frl.required_lanes;
+	enum drm_scdc_frl_ltp ltp[4];
+	u32 write_buf = 0;
+	int lane;
+
+	if (!(get_frl_update_flags(encoder) & SCDC_FLT_UPDATE))
+		return FRL_TRAIN_CONTINUE;
+
+	if (get_link_training_patterns(encoder, ltp) < 0)
+		return FRL_TRAIN_STOP;
+
+	if (ltp[0] == ltp[1] && ltp[1] == ltp[2]) {
+		if (num_lanes == 3 || (num_lanes == 4 && ltp[2] == ltp[3])) {
+			if (ltp[0] == SCDC_FRL_NO_LTP)
+				return FRL_TRAINING_PASSED;
+			if (ltp[0] == SCDC_FRL_CHNG_RATE)
+				return FRL_CHANGE_RATE;
+		}
+	}
+
+	for (lane = 0; lane < num_lanes; lane++) {
+		if (ltp[lane] >= SCDC_FRL_LTP1 && ltp[lane] <= SCDC_FRL_LTP8)
+			write_buf |= TRANS_HDMI_FRL_LTP(ltp[lane], lane);
+		/* #TODO handle FFE change */
+		else if (ltp[lane] == SCDC_FRL_CHNG_FFE)
+			continue;
+	}
+
+	intel_de_write(display, TRANS_HDMI_FRL_TRAIN(display, trans), write_buf);
+
+	clear_scdc_update_flags(encoder, SCDC_FLT_UPDATE);
+
+	return FRL_TRAIN_CONTINUE;
+}
+
+static enum frl_lt_status
+frl_train_complete_ltsp(struct intel_encoder *encoder,
+			const struct intel_crtc_state *crtc_state)
+{
+#define FLT_UPDATE_TIMEOUT_MS 200
+	struct intel_display *display = to_intel_display(encoder);
+	enum transcoder trans = crtc_state->cpu_transcoder;
+	u8 update_flags = 0, clear_flags = 0;
+	u32 buf;
+
+	buf = intel_de_read(display, TRANS_HDMI_FRL_CFG(display, trans));
+	intel_de_write(display, TRANS_HDMI_FRL_CFG(display, trans),
+		       buf | TRANS_HDMI_FRL_TRAINING_COMPLETE);
+
+	if (clear_scdc_update_flags(encoder, SCDC_FLT_UPDATE) < 0)
+		return FRL_TRAIN_STOP;
+
+	if (!read_poll_timeout(get_frl_update_flags, update_flags,
+			       update_flags & (SCDC_FRL_START | SCDC_FLT_UPDATE),
+			       1000, FLT_UPDATE_TIMEOUT_MS * USEC_PER_MSEC,
+			       false, encoder)) {
+		if (update_flags & SCDC_FLT_UPDATE)
+			clear_flags |= SCDC_FLT_UPDATE;
+		if (update_flags & SCDC_FRL_START) {
+			clear_flags |= SCDC_FRL_START;
+			clear_scdc_update_flags(encoder, clear_flags);
+			return FRL_TRAINING_PASSED;
+		}
+		drm_dbg_kms(display->drm,
+			    "FRL update received for retraining the lanes\n");
+		clear_scdc_update_flags(encoder, clear_flags);
+		return FRL_TRAIN_RETRAIN;
+	}
+
+	drm_err(display->drm, "FRL TRAINING: FRL update timedout\n");
+	return FRL_TRAIN_STOP;
+}
+
+static enum frl_lt_status
+intel_hdmi_frl_train_lts3(struct intel_encoder *encoder,
+			  const struct intel_crtc_state *crtc_state,
+			  int ffe_level)
+{
+#define FLT_TIMEOUT_MS 200
+	struct intel_display *display = to_intel_display(encoder);
+	enum frl_lt_status status;
+	enum transcoder trans = crtc_state->cpu_transcoder;
+	u32 buf;
+
+	buf = intel_de_read(display, TRANS_HDMI_FRL_CFG(display, trans));
+	intel_de_write(display, TRANS_HDMI_FRL_CFG(display, trans),
+		       buf | TRANS_HDMI_FRL_ENABLE);
+
+#define done (status != FRL_TRAIN_CONTINUE)
+	status = FRL_TRAIN_CONTINUE;
+	read_poll_timeout(intel_hdmi_train_lanes, status,
+			  done,
+			  1000, FLT_TIMEOUT_MS * USEC_PER_MSEC,
+			  false, encoder, crtc_state, ffe_level);
+
+	if (status == FRL_TRAIN_CONTINUE) {
+		drm_err(display->drm, "FRL TRAINING: FLT TIMEDOUT\n");
+		return FRL_TRAIN_STOP;
+	}
+
+	if (status != FRL_TRAINING_PASSED)
+		return status;
+
+	return frl_train_complete_ltsp(encoder, crtc_state);
+}
+
+static int get_ffe_level(int rate_gbps)
+{
+	return 0;
+}
+
+int intel_hdmi_start_frl(struct intel_encoder *encoder,
+			 const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+	struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
+	struct intel_connector *intel_connector = intel_hdmi->attached_connector;
+	struct drm_connector *connector = &intel_connector->base;
+	int req_rate = crtc_state->frl.required_lanes * crtc_state->frl.required_rate;
+	int ffe_level = get_ffe_level(req_rate);
+	enum frl_lt_status status;
+
+	if (!crtc_state->frl.enable)
+		return 0;
+
+	if (intel_hdmi->frl.trained &&
+	    intel_hdmi->frl.rate_gbps >= req_rate) {
+		drm_dbg_kms(display->drm,
+			    "[CONNECTOR:%d:%s] FRL Already trained with rate=%d\n",
+			    connector->base.id, connector->name,
+			    intel_hdmi->frl.rate_gbps);
+		return 0;
+	}
+
+	intel_hdmi_reset_frl_config(intel_hdmi);
+
+	if (!intel_hdmi_frl_prepare_lts2(encoder,
+					 crtc_state->frl.required_rate,
+					 crtc_state->frl.required_lanes,
+					 ffe_level))
+		status = FRL_TRAIN_STOP;
+	else
+		status = intel_hdmi_frl_train_lts3(encoder, crtc_state, ffe_level);
+
+	switch (status) {
+	case FRL_TRAINING_PASSED:
+		intel_hdmi->frl.trained = true;
+		intel_hdmi->frl.rate_gbps = req_rate;
+		intel_hdmi->frl.ffe_level = ffe_level;
+		drm_dbg_kms(display->drm,
+			    "[CONNECTOR:%d:%s] FRL Training Passed with rate=%d\n",
+			    connector->base.id, connector->name,
+			    intel_hdmi->frl.rate_gbps);
+		return 0;
+	default:
+		break;
+	}
+
+	if (crtc_state->frl.enable && !intel_hdmi->frl.trained)
+		drm_err(display->drm,
+			"[CONNECTOR:%d:%s] FRL Training Failed with rate=%d\n",
+			connector->base.id, connector->name,
+			req_rate);
+
+	return -EINVAL;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 6283305b5274..1724e6075a9b 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -64,6 +64,8 @@ int intel_hdmi_dsc_get_num_slices(const struct drm_display_mode *mode,
 int intel_hdmi_dsc_get_slice_height(int vactive);
 bool intel_hdmi_is_frl(u32 clock);
 void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state);
+int intel_hdmi_start_frl(struct intel_encoder *encoder,
+			 const struct intel_crtc_state *crtc_state);
 void hsw_write_infoframe(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state,
 			 unsigned int type,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 15/44] drm/i915/intel_hdmi: Add helper to disable FRL
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (13 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 16/44] drm/i915/hdmi: Reduce FRL rate cap on rate change during training Ankit Nautiyal
                   ` (29 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add function to reset the SCDC FRL configuration and
Transcoder FRL configuration registers.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 28 +++++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_hdmi.h |  2 ++
 2 files changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index ff200d662a3f..fe4923c82463 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3781,3 +3781,31 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 
 	return -EINVAL;
 }
+
+static void intel_hdmi_frl_ltsl(struct intel_encoder *encoder,
+				const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(display, intel_hdmi_ddc_pin(encoder));
+
+	drm_scdc_disable_frl(adapter);
+	drm_scdc_clear_update_flags(adapter, SCDC_FLT_UPDATE);
+}
+
+void intel_hdmi_disable_frl(struct intel_encoder *encoder,
+			    const struct intel_crtc_state *crtc_state)
+{
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_display *display = to_intel_display(encoder);
+	enum transcoder trans = crtc_state->cpu_transcoder;
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	intel_hdmi_frl_ltsl(encoder, crtc_state);
+	intel_de_rmw(display, TRANS_HDMI_FRL_CFG(display, trans),
+		     TRANS_HDMI_FRL_ENABLE | TRANS_HDMI_FRL_TRAINING_COMPLETE, 0);
+
+	intel_hdmi_reset_frl_config(intel_hdmi);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 1724e6075a9b..59a561ad28e0 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -66,6 +66,8 @@ bool intel_hdmi_is_frl(u32 clock);
 void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state);
 int intel_hdmi_start_frl(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state);
+void intel_hdmi_disable_frl(struct intel_encoder *encoder,
+			    const struct intel_crtc_state *crtc_state);
 void hsw_write_infoframe(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state,
 			 unsigned int type,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 16/44] drm/i915/hdmi: Reduce FRL rate cap on rate change during training
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (14 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 15/44] drm/i915/intel_hdmi: Add helper to disable FRL Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 17/44] drm/i915/hdmi: Introduce intel_hdmi_frl_level() for per-lane TxFFE Ankit Nautiyal
                   ` (28 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

If the sink requests a rate change during FRL Link training, reduce
frl.rate_cap to the next lower FRL rate. The next mode compute then
uses this lower rate cap, so we do not attempt the failing rate again.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 27 ++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index fe4923c82463..2b0cdb0719e2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3720,6 +3720,18 @@ intel_hdmi_frl_train_lts3(struct intel_encoder *encoder,
 	return frl_train_complete_ltsp(encoder, crtc_state);
 }
 
+static int get_next_frl_rate(int curr_rate_gbps)
+{
+	int valid_rate[] = { 48, 40, 32, 24, 18, 9 };
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(valid_rate); i++)
+		if (valid_rate[i] < curr_rate_gbps)
+			return valid_rate[i];
+
+	return -EINVAL;
+}
+
 static int get_ffe_level(int rate_gbps)
 {
 	return 0;
@@ -3736,6 +3748,7 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 	int req_rate = crtc_state->frl.required_lanes * crtc_state->frl.required_rate;
 	int ffe_level = get_ffe_level(req_rate);
 	enum frl_lt_status status;
+	int next_rate = -EINVAL;
 
 	if (!crtc_state->frl.enable)
 		return 0;
@@ -3769,10 +3782,22 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 			    connector->base.id, connector->name,
 			    intel_hdmi->frl.rate_gbps);
 		return 0;
-	default:
+	case FRL_TRAIN_STOP:
+		next_rate = 0;
+		break;
+	case FRL_CHANGE_RATE:
+		next_rate = get_next_frl_rate(req_rate);
 		break;
+	case FRL_TRAIN_RETRAIN:
+		fallthrough;
+	default:
+		goto ltsl_tmds_mode;
 	}
 
+	if (next_rate >= 0)
+		intel_hdmi->frl.rate_cap = next_rate;
+
+ltsl_tmds_mode:
 	if (crtc_state->frl.enable && !intel_hdmi->frl.trained)
 		drm_err(display->drm,
 			"[CONNECTOR:%d:%s] FRL Training Failed with rate=%d\n",
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 17/44] drm/i915/hdmi: Introduce intel_hdmi_frl_level() for per-lane TxFFE
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (15 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 18/44] drm/i915/hdmi: Drive per-lane TxFFE during FRL link training Ankit Nautiyal
                   ` (27 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

HDMI FRL link training tracks the TxFFE preset per lane: the sink
issues per-lane Ln(x)_LTP_req requests over SCDC and the source owns
an independent TxFFE counter for each lane.
The PHY HDMI FRL buf-trans table is laid out so that index 1 + 3*N
selects the normal-operation row for TxFFE level N.

Convert struct intel_hdmi.frl from a single link-wide ffe_level into
a per-lane ffe_level[4] array plus a max_ffe_level cap, and expose
intel_hdmi_frl_level(encoder, lane) which returns the buf-trans index
that the PHY set_signal_levels() callback should program for that
lane.

Wire it into intel_ddi_level(): on FRL the per-lane index is used,
TMDS keeps the existing intel_ddi_hdmi_level() VBT/default path.

No functional change yet: ffe_level[] is always zero, so
intel_hdmi_frl_level() returns the TxFFE0 row (index 1) on every
lane, matching pre-existing behaviour. The training-side updates
that drive ffe_level[] arrive in a follow-up patch.

Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c      | 10 +++++---
 .../drm/i915/display/intel_display_types.h    |  3 ++-
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 25 +++++++++++++++++--
 drivers/gpu/drm/i915/display/intel_hdmi.h     |  2 ++
 4 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index d6e7e7863d36..d1a60cdf55fa 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -1517,11 +1517,15 @@ int intel_ddi_level(struct intel_encoder *encoder,
 	if (drm_WARN_ON_ONCE(display->drm, !trans))
 		return 0;
 
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
-		level = intel_ddi_hdmi_level(encoder, trans);
-	else
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+		if (intel_hdmi_is_frl(crtc_state->port_clock))
+			level = intel_hdmi_frl_level(encoder, lane);
+		else
+			level = intel_ddi_hdmi_level(encoder, trans);
+	} else {
 		level = intel_ddi_dp_level(enc_to_intel_dp(encoder), crtc_state,
 					   lane);
+	}
 
 	if (drm_WARN_ON_ONCE(display->drm, level >= n_entries))
 		level = n_entries - 1;
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 00775ad9019c..942dbad802a6 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1722,9 +1722,10 @@ struct intel_hdmi {
 		bool trained;
 		int lanes;
 		int rate_gbps;
-		int ffe_level;
 		int rate_cap;
 		bool reset_rate_cap;
+		u8 max_ffe_level;
+		u8 ffe_level[4];
 	} frl;
 };
 
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 2b0cdb0719e2..ba1543023373 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2554,7 +2554,27 @@ intel_hdmi_reset_frl_config(struct intel_hdmi *intel_hdmi)
 	intel_hdmi->frl.trained = false;
 	intel_hdmi->frl.lanes = 0;
 	intel_hdmi->frl.rate_gbps = 0;
-	intel_hdmi->frl.ffe_level = 0;
+	intel_hdmi->frl.max_ffe_level = 0;
+	memset(intel_hdmi->frl.ffe_level, 0, sizeof(intel_hdmi->frl.ffe_level));
+}
+
+/*
+ * HDMI FRL training level is encoded as follows:
+ *   i 0      : No FFE (LTP4 test mode)
+ *   i 1+3*N  : TxFFE N normal operation (N = 0..3)
+ *   i 1+3*N+1: TxFFE N de-emphasis only (LTP4 test mode)
+ *   i 1+3*N+2: TxFFE N pre-shoot only  (LTP4 test mode)
+ *
+ * Normal operation returns 1 + 3 * ffe_level[lane].
+ */
+int intel_hdmi_frl_level(struct intel_encoder *encoder, int lane)
+{
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+
+	if (lane < 0 || lane >= ARRAY_SIZE(intel_hdmi->frl.ffe_level))
+		return 1;
+
+	return 1 + 3 * intel_hdmi->frl.ffe_level[lane];
 }
 
 static void
@@ -3763,6 +3783,7 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 	}
 
 	intel_hdmi_reset_frl_config(intel_hdmi);
+	intel_hdmi->frl.max_ffe_level = ffe_level;
 
 	if (!intel_hdmi_frl_prepare_lts2(encoder,
 					 crtc_state->frl.required_rate,
@@ -3776,7 +3797,7 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 	case FRL_TRAINING_PASSED:
 		intel_hdmi->frl.trained = true;
 		intel_hdmi->frl.rate_gbps = req_rate;
-		intel_hdmi->frl.ffe_level = ffe_level;
+		intel_hdmi->frl.max_ffe_level = ffe_level;
 		drm_dbg_kms(display->drm,
 			    "[CONNECTOR:%d:%s] FRL Training Passed with rate=%d\n",
 			    connector->base.id, connector->name,
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 59a561ad28e0..5baa38d326e5 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -68,6 +68,8 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state);
 void intel_hdmi_disable_frl(struct intel_encoder *encoder,
 			    const struct intel_crtc_state *crtc_state);
+void intel_hdmi_prepare_for_frl_mode(const struct intel_crtc_state *crtc_state);
+int intel_hdmi_frl_level(struct intel_encoder *encoder, int lane);
 void hsw_write_infoframe(struct intel_encoder *encoder,
 			 const struct intel_crtc_state *crtc_state,
 			 unsigned int type,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 18/44] drm/i915/hdmi: Drive per-lane TxFFE during FRL link training
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (16 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 19/44] drm/i915/ltphy: Add PLL tables for HDMI FRL Ankit Nautiyal
                   ` (26 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

Hook the per-lane TxFFE state added by the previous patch into the
HDMI FRL Link Training Sequence (LTS:3):

 - Advertise FFE_Levels=3 (TxFFE0..TxFFE3) in SCDC 0x31, matching the
   four TxFFE rows present in the PHY HDMI FRL buf-trans table.

 - On LTS:3 entry, after enabling TRANS_HDMI_FRL_ENABLE, call
   encoder->set_signal_levels() so the PHY is programmed to TxFFE0
   on every lane before the sink starts emitting Ln(x)_LTP_req.

 - In intel_hdmi_train_lanes(), handle SCDC_FRL_CHNG_FFE (0xE) by
   incrementing intel_hdmi->frl.ffe_level[lane], capped at
   max_ffe_level. When any lane changed, reprogram the PHY via
   encoder->set_signal_levels() before acknowledging the request.

 - Always clear SCDC FLT_update (0x10 bit 5) after acting on a sink
   request, as required by the HDMI spec.

A forward declaration of clear_scdc_update_flags() is added so it
can be called from intel_hdmi_train_lanes() without reordering the
file.

Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 39 +++++++++++++++++++----
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index ba1543023373..db585c2af21d 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3573,6 +3573,7 @@ static int clear_scdc_update_flags(struct intel_encoder *encoder, u8 flags)
 
 static bool
 intel_hdmi_frl_prepare_lts2(struct intel_encoder *encoder,
+			    const struct intel_crtc_state *crtc_state,
 			    int frl_rate, int frl_lanes,
 			    int ffe_level)
 {
@@ -3598,7 +3599,12 @@ intel_hdmi_frl_prepare_lts2(struct intel_encoder *encoder,
 	if ((get_frl_update_flags(encoder) & SCDC_FLT_UPDATE))
 		clear_scdc_update_flags(encoder, SCDC_FLT_UPDATE);
 
-	/* #TODO: Source shall program TxFFE = 0 for all active lanes */
+	/*
+	 * Program PHY to TxFFE0 on every lane before the sink
+	 * starts evaluating LTP patterns. ffe_level[] has already been
+	 * cleared by intel_hdmi_reset_frl_config().
+	 */
+	encoder->set_signal_levels(encoder, crtc_state);
 
 	if (drm_scdc_config_frl(adapter, frl_rate, frl_lanes, ffe_level) < 0) {
 		drm_dbg_kms(display->drm,
@@ -3633,9 +3639,11 @@ intel_hdmi_train_lanes(struct intel_encoder *encoder,
 		       int ffe_level)
 {
 	struct intel_display *display = to_intel_display(encoder);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	enum transcoder trans = crtc_state->cpu_transcoder;
 	int num_lanes = crtc_state->frl.required_lanes;
 	enum drm_scdc_frl_ltp ltp[4];
+	bool ffe_changed = false;
 	u32 write_buf = 0;
 	int lane;
 
@@ -3657,13 +3665,29 @@ intel_hdmi_train_lanes(struct intel_encoder *encoder,
 	for (lane = 0; lane < num_lanes; lane++) {
 		if (ltp[lane] >= SCDC_FRL_LTP1 && ltp[lane] <= SCDC_FRL_LTP8)
 			write_buf |= TRANS_HDMI_FRL_LTP(ltp[lane], lane);
-		/* #TODO handle FFE change */
-		else if (ltp[lane] == SCDC_FRL_CHNG_FFE)
-			continue;
+		else if (ltp[lane] == SCDC_FRL_CHNG_FFE) {
+			/*
+			 * During FRL link training: Sink requests Source
+			 * to step TxFFE up by one for this lane. Cap at the
+			 * advertised max FFE level.
+			 */
+			if (intel_hdmi->frl.ffe_level[lane] <
+			    intel_hdmi->frl.max_ffe_level) {
+				intel_hdmi->frl.ffe_level[lane]++;
+				ffe_changed = true;
+			}
+		}
 	}
 
 	intel_de_write(display, TRANS_HDMI_FRL_TRAIN(display, trans), write_buf);
 
+	/*
+	 * Reprogram per-lane PHY TxFFE before clearing FLT_update so the
+	 * sink evaluates the new preset on the next iteration.
+	 */
+	if (ffe_changed)
+		encoder->set_signal_levels(encoder, crtc_state);
+
 	clear_scdc_update_flags(encoder, SCDC_FLT_UPDATE);
 
 	return FRL_TRAIN_CONTINUE;
@@ -3752,9 +3776,9 @@ static int get_next_frl_rate(int curr_rate_gbps)
 	return -EINVAL;
 }
 
-static int get_ffe_level(int rate_gbps)
+static int get_max_ffe_level(int rate_gbps)
 {
-	return 0;
+	return 3;
 }
 
 int intel_hdmi_start_frl(struct intel_encoder *encoder,
@@ -3766,7 +3790,7 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 	struct intel_connector *intel_connector = intel_hdmi->attached_connector;
 	struct drm_connector *connector = &intel_connector->base;
 	int req_rate = crtc_state->frl.required_lanes * crtc_state->frl.required_rate;
-	int ffe_level = get_ffe_level(req_rate);
+	int ffe_level = get_max_ffe_level(req_rate);
 	enum frl_lt_status status;
 	int next_rate = -EINVAL;
 
@@ -3786,6 +3810,7 @@ int intel_hdmi_start_frl(struct intel_encoder *encoder,
 	intel_hdmi->frl.max_ffe_level = ffe_level;
 
 	if (!intel_hdmi_frl_prepare_lts2(encoder,
+					 crtc_state,
 					 crtc_state->frl.required_rate,
 					 crtc_state->frl.required_lanes,
 					 ffe_level))
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 19/44] drm/i915/ltphy: Add PLL tables for HDMI FRL
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (17 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 20/44] drm/i915/ltphy: Add safegaurd when calculation HDMI FRL state Ankit Nautiyal
                   ` (25 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

Add HDMI FRL Tables for LT PHY i.e for the rates of 3G, 6G, 8G,
10G and 12G.

Bspec: 74667
Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_lt_phy.c | 270 ++++++++++++++++++++
 1 file changed, 270 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index 8fc6d230493f..a16401e42ed9 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -950,11 +950,281 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_5p94 = {
 	},
 };
 
+static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_3g0 = {
+	.config = {
+		0x85,
+		0x2d,
+		0x0,
+	},
+	.addr_msb = {
+		0x87,
+		0x87,
+		0x87,
+		0x87,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+	},
+	.addr_lsb = {
+		0x10,
+		0x0c,
+		0x14,
+		0xe4,
+		0x0c,
+		0x10,
+		0x14,
+		0x18,
+		0x48,
+		0x40,
+		0x4c,
+		0x24,
+		0x44,
+	},
+	.data = {
+		{ 0x0,  0x4c, 0x2,  0x0  },
+		{ 0x5,  0xa,  0x27, 0x0  },
+		{ 0x80, 0x0,  0x0,  0x0  },
+		{ 0x4,  0x9,  0x1,  0x28 },
+		{ 0xf2, 0x2e, 0x83, 0x10 },
+		{ 0x80, 0x0f, 0xf9, 0x53 },
+		{ 0x84, 0x24, 0x0,  0x0  },
+		{ 0x0,  0xe0, 0x1,  0x0  },
+		{ 0x4b, 0x48, 0x0,  0x0  },
+		{ 0x27, 0x8,  0x0,  0x0  },
+		{ 0x5a, 0x13, 0x29, 0x13 },
+		{ 0x0,  0x40, 0xa0, 0x0  },
+		{ 0x0,  0x0,  0x0,  0x0  },
+	},
+};
+
+static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_6g0 = {
+	.config = {
+		0x8d,
+		0x2d,
+		0x0,
+	},
+	.addr_msb = {
+		0x87,
+		0x87,
+		0x87,
+		0x87,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+	},
+	.addr_lsb = {
+		0x10,
+		0x0c,
+		0x14,
+		0xe4,
+		0x0c,
+		0x10,
+		0x14,
+		0x18,
+		0x48,
+		0x40,
+		0x4c,
+		0x24,
+		0x44,
+	},
+	.data = {
+		{ 0x0,  0x4c, 0x2,  0x0  },
+		{ 0x2,  0x8a, 0x27, 0x0  },
+		{ 0x80, 0x0,  0x0,  0x0  },
+		{ 0x4,  0x4,  0x80, 0xa8 },
+		{ 0xf2, 0x2e, 0x83, 0x10 },
+		{ 0x80, 0x0f, 0xf9, 0x53 },
+		{ 0x84, 0x24, 0x0,  0x0  },
+		{ 0x0,  0xe0, 0x1,  0x0  },
+		{ 0x4b, 0x48, 0x0,  0x0  },
+		{ 0x27, 0x8,  0x0,  0x0  },
+		{ 0x5a, 0x13, 0x29, 0x13 },
+		{ 0x0,  0x40, 0xa0, 0x0  },
+		{ 0x0,  0x0,  0x0,  0x0  },
+	},
+};
+
+static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_8g0 = {
+	.config = {
+		0x95,
+		0x2d,
+		0x0,
+	},
+	.addr_msb = {
+		0x87,
+		0x87,
+		0x87,
+		0x87,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+	},
+	.addr_lsb = {
+		0x10,
+		0x0c,
+		0x14,
+		0xe4,
+		0x0c,
+		0x10,
+		0x14,
+		0x18,
+		0x48,
+		0x40,
+		0x4c,
+		0x24,
+		0x44,
+	},
+	.data = {
+		{ 0x0,  0x4c, 0x2,  0x0  },
+		{ 0x2,  0x8a, 0x34, 0x0  },
+		{ 0xaa, 0xaa, 0xaa, 0xaa },
+		{ 0x5,  0x4,  0x80, 0xa8 },
+		{ 0xf2, 0x22, 0x83, 0x10 },
+		{ 0x80, 0x0f, 0xf9, 0xb5 },
+		{ 0x84, 0x24, 0x0,  0x0  },
+		{ 0x0,  0xe0, 0x1,  0x0  },
+		{ 0x4b, 0x48, 0x0,  0x0  },
+		{ 0x27, 0x8,  0x0,  0x0  },
+		{ 0x5a, 0x13, 0x29, 0x13 },
+		{ 0x0,  0x40, 0xa0, 0x0  },
+		{ 0x0,  0x0,  0x0,  0x0  },
+	},
+};
+
+static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_10g0 = {
+	.config = {
+		0x1d,
+		0x2d,
+		0x0,
+	},
+	.addr_msb = {
+		0x85,
+		0x85,
+		0x85,
+		0x85,
+		0x86,
+		0x86,
+		0x86,
+		0x86,
+		0x86,
+		0x00,
+		0x86,
+		0x86,
+		0x86,
+	},
+	.addr_lsb = {
+		0x10,
+		0x0c,
+		0x14,
+		0xe4,
+		0x0c,
+		0x10,
+		0x14,
+		0x18,
+		0x48,
+		0x00,
+		0x4c,
+		0x24,
+		0x44,
+	},
+	.data = {
+		{ 0x0,  0x4c, 0x2,  0x0  },
+		{ 0x1,  0x49, 0x20, 0x80 },
+		{ 0x6a, 0xaa, 0xaa, 0xab },
+		{ 0x0,  0x6,  0x4,  0x94 },
+		{ 0xfa, 0x1c, 0x83, 0x11 },
+		{ 0x80, 0x0f, 0xf9, 0x53 },
+		{ 0x84, 0x26, 0x4,  0x4  },
+		{ 0x0,  0xe0, 0x1,  0x0  },
+		{ 0x45, 0x48, 0x0,  0x0  },
+		{ 0x27, 0x8,  0x0,  0x0  },
+		{ 0x5a, 0x14, 0x2a, 0x14 },
+		{ 0x0,  0x5b, 0xe0, 0x8  },
+		{ 0x0,  0x0,  0x0,  0x0  },
+	},
+};
+
+static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_12g0 = {
+	.config = {
+		0xa5,
+		0x2d,
+		0x0,
+	},
+	.addr_msb = {
+		0x87,
+		0x87,
+		0x87,
+		0x87,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+		0x88,
+	},
+	.addr_lsb = {
+		0x10,
+		0x0c,
+		0x14,
+		0xe4,
+		0x0c,
+		0x10,
+		0x14,
+		0x18,
+		0x48,
+		0x40,
+		0x4c,
+		0x24,
+		0x44,
+	},
+	.data = {
+		{ 0x0,  0x4c, 0x2,  0x0  },
+		{ 0x1,  0x49, 0x27, 0x0  },
+		{ 0x80, 0x0,  0x0,  0x0  },
+		{ 0x8,  0x4,  0x80, 0xb2 },
+		{ 0xf2, 0x2e, 0x83, 0x10 },
+		{ 0x80, 0x0f, 0xf9, 0x53 },
+		{ 0x84, 0x24, 0x0,  0x0  },
+		{ 0x0,  0xe0, 0x1,  0x0  },
+		{ 0x4b, 0x48, 0x0,  0x0  },
+		{ 0x27, 0x8,  0x0,  0x0  },
+		{ 0x5a, 0x14, 0x29, 0x14 },
+		{ 0x0,  0x40, 0xa0, 0x0  },
+		{ 0x0,  0x0,  0x0,  0x0  },
+	},
+};
+
 static const struct intel_lt_phy_pll_params xe3plpd_lt_hdmi_tables[] = {
 	LT_PHY_PLL_HDMI_PARAMS(25200, xe3plpd_lt_hdmi_252),
 	LT_PHY_PLL_HDMI_PARAMS(74250, xe3plpd_lt_hdmi_742p5),
 	LT_PHY_PLL_HDMI_PARAMS(148500, xe3plpd_lt_hdmi_1p485),
 	LT_PHY_PLL_HDMI_PARAMS(594000, xe3plpd_lt_hdmi_5p94),
+	LT_PHY_PLL_HDMI_PARAMS(300000, xe3plpd_lt_hdmi_3g0),
+	LT_PHY_PLL_HDMI_PARAMS(600000, xe3plpd_lt_hdmi_6g0),
+	LT_PHY_PLL_HDMI_PARAMS(800000, xe3plpd_lt_hdmi_8g0),
+	LT_PHY_PLL_HDMI_PARAMS(1000000, xe3plpd_lt_hdmi_10g0),
+	LT_PHY_PLL_HDMI_PARAMS(1200000, xe3plpd_lt_hdmi_12g0),
 	{}
 };
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 20/44] drm/i915/ltphy: Add safegaurd when calculation HDMI FRL state
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (18 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 19/44] drm/i915/ltphy: Add PLL tables for HDMI FRL Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 21/44] drm/i915/ltphy: Calculate port clock for HDMI FRL Ankit Nautiyal
                   ` (24 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

intel_lt_phy_pll_calc_state() will also take into account the
HDMI FRL tables and use them when the DPLL matches. We
still add a safegaurd to not calculate hdmi pll state if we are
using HDMI FRL.

Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_lt_phy.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index a16401e42ed9..88b86510e28a 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -2042,7 +2042,8 @@ intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state,
 		}
 	}
 
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
+	    !intel_hdmi_is_frl(crtc_state->port_clock)) {
 		hw_state->ltpll.lane_count = crtc_state->lane_count;
 		return intel_lt_phy_calculate_hdmi_state(&hw_state->ltpll,
 							 crtc_state->port_clock);
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 21/44] drm/i915/ltphy: Calculate port clock for HDMI FRL
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (19 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 22/44] drm/i915/ltphy: Verify HDMI FRL tables Ankit Nautiyal
                   ` (23 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

Define function to get the port clock after we read VDR0_CONFIG.
This helps us determine the port clock for HDMI FRL use case in LT
PHY.

Bspec: 74667, 74500
Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_lt_phy.c | 23 +++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index 88b86510e28a..918ecb14fb5c 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -1501,6 +1501,25 @@ intel_lt_phy_program_port_clock_ctl(struct intel_encoder *encoder,
 		     XELPDP_SSC_ENABLE_PLLB, val);
 }
 
+static u32 intel_lt_phy_get_hdmi_frl_clock(u8 rate)
+{
+	switch (rate) {
+	case 0:
+		return 300000;
+	case 1:
+		return 600000;
+	case 2:
+		return 800000;
+	case 3:
+		return 1000000;
+	case 4:
+		return 1200000;
+	default:
+		MISSING_CASE(rate);
+		return 0;
+	}
+}
+
 static u32 intel_lt_phy_get_dp_clock(u8 rate)
 {
 	switch (rate) {
@@ -2000,6 +2019,10 @@ intel_lt_phy_calc_port_clock(struct intel_display *display,
 		rate = REG_FIELD_GET8(LT_PHY_VDR_RATE_ENCODING_MASK,
 				      lt_state->config[0]);
 		clk = intel_lt_phy_get_dp_clock(rate);
+	} else if (mode == MODE_HDMI_FRL) {
+		rate = REG_FIELD_GET8(LT_PHY_VDR_RATE_ENCODING_MASK,
+				      lt_state->config[0]);
+		clk = intel_lt_phy_get_hdmi_frl_clock(rate);
 	} else if (mode == MODE_HDMI_20) {
 		clk = intel_lt_phy_calc_hdmi_port_clock(display, lt_state);
 	} else {
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 22/44] drm/i915/ltphy: Verify HDMI FRL tables
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (20 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 21/44] drm/i915/ltphy: Calculate port clock for HDMI FRL Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 23/44] drm/i915/ddi_buf: Add Vswing table for HDMI FRL Ankit Nautiyal
                   ` (22 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

Verify the HDMI FRL tables now that they are defined.
Also skip recalculating the HDMI state via port clock for HDMI
FRL use case.

Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_lt_phy.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index 918ecb14fb5c..2c1da689fe00 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -2628,6 +2628,9 @@ static void intel_lt_phy_pll_verify_params(struct intel_display *display,
 	if (!pll_params->is_hdmi)
 		return;
 
+	if (intel_hdmi_is_frl(pll_params->clock_rate))
+		return;
+
 	if (intel_lt_phy_calculate_hdmi_state(&pll_state, pll_params->clock_rate) != 0)
 		return;
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 23/44] drm/i915/ddi_buf: Add Vswing table for HDMI FRL
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (21 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 22/44] drm/i915/ltphy: Verify HDMI FRL tables Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 24/44] drm/i915/hdmi: Add provision for FRL mode while computing output format Ankit Nautiyal
                   ` (21 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Suraj Kandpal <suraj.kandpal@intel.com>

Define Vswing table for HDMI FRL to set the signal levels.
This is done for LT PHY which is Xe3PLPD onwards.

Bspec: 74493
Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
---
 .../drm/i915/display/intel_ddi_buf_trans.c    | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
index 4cd1e4d76c7a..e7f40f1a7eac 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
@@ -10,6 +10,7 @@
 #include "intel_display_types.h"
 #include "intel_display_utils.h"
 #include "intel_dp.h"
+#include "intel_hdmi.h"
 #include "intel_lt_phy.h"
 
 /* HDMI/DVI modes ignore everything but the last 2 items. So we share
@@ -1164,6 +1165,22 @@ static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_edp[] = {
 	{ .lt = { 1, 3, 0, 26, 0 } },
 };
 
+static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_hdmi_frl[] = {
+	{ .lt = { 0, 0, 0, 48, 0  } },
+	{ .lt = { 0, 0, 4, 38, 6  } },
+	{ .lt = { 0, 0, 0, 42, 6  } },
+	{ .lt = { 0, 0, 4, 44, 0  } },
+	{ .lt = { 0, 0, 4, 36, 8  } },
+	{ .lt = { 0, 0, 0, 40, 8  } },
+	{ .lt = { 0, 0, 4, 44, 0  } },
+	{ .lt = { 0, 0, 4, 34, 10 } },
+	{ .lt = { 0, 0, 0, 38, 10 } },
+	{ .lt = { 0, 0, 4, 44, 0  } },
+	{ .lt = { 0, 0, 4, 32, 12 } },
+	{ .lt = { 0, 0, 0, 36, 12 } },
+	{ .lt = { 0, 0, 4, 44, 0  } },
+};
+
 static const struct intel_ddi_buf_trans xe3plpd_lt_trans_dp14 = {
 	.entries = _xe3plpd_lt_trans_dp14,
 	.num_entries = ARRAY_SIZE(_xe3plpd_lt_trans_dp14),
@@ -1179,6 +1196,11 @@ static const struct intel_ddi_buf_trans xe3plpd_lt_trans_edp = {
 	.num_entries = ARRAY_SIZE(_xe3plpd_lt_trans_edp),
 };
 
+static const struct intel_ddi_buf_trans xe3plpd_lt_trans_hdmi_frl = {
+	.entries = _xe3plpd_lt_trans_hdmi_frl,
+	.num_entries = ARRAY_SIZE(_xe3plpd_lt_trans_hdmi_frl),
+};
+
 bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table)
 {
 	return table == &tgl_combo_phy_trans_edp_hbr2_hobl;
@@ -1780,6 +1802,9 @@ xe3plpd_get_lt_buf_trans(struct intel_encoder *encoder,
 		return intel_get_buf_trans(&xe3plpd_lt_trans_uhbr, n_entries);
 	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
 		return intel_get_buf_trans(&xe3plpd_lt_trans_edp, n_entries);
+	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
+		 intel_hdmi_is_frl(crtc_state->port_clock))
+		return intel_get_buf_trans(&xe3plpd_lt_trans_hdmi_frl, n_entries);
 	else
 		return intel_get_buf_trans(&xe3plpd_lt_trans_dp14, n_entries);
 }
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 24/44] drm/i915/hdmi: Add provision for FRL mode while computing output format
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (22 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 25/44] drm/i915/hdmi: Rename port clock limit to specify tmds clock Ankit Nautiyal
                   ` (20 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Add a check in compute_config to select FRL mode when TMDS cannot
support the required bandwidth, passing frl_mode flag to the output
format computation.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 34 +++++++++++++++++------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index db585c2af21d..8f0ee9282b61 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2195,9 +2195,9 @@ static int intel_hdmi_compute_bpc(struct intel_encoder *encoder,
 	return -EINVAL;
 }
 
-static int intel_hdmi_compute_clock(struct intel_encoder *encoder,
-				    struct intel_crtc_state *crtc_state,
-				    bool respect_downstream_limits)
+static int intel_hdmi_compute_tmds_clock(struct intel_encoder *encoder,
+					 struct intel_crtc_state *crtc_state,
+					 bool respect_downstream_limits)
 {
 	struct intel_display *display = to_intel_display(encoder);
 	const struct drm_display_mode *adjusted_mode =
@@ -2229,6 +2229,17 @@ static int intel_hdmi_compute_clock(struct intel_encoder *encoder,
 	return 0;
 }
 
+static int intel_hdmi_compute_clock(struct intel_encoder *encoder,
+				    struct intel_crtc_state *crtc_state,
+				    bool respect_downstream_limits,
+				    bool enable_frl)
+{
+	if (enable_frl)
+		return -EINVAL;
+
+	return intel_hdmi_compute_tmds_clock(encoder, crtc_state, respect_downstream_limits);
+}
+
 bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
 				    const struct drm_connector_state *conn_state)
 {
@@ -2284,7 +2295,8 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
 					    struct intel_crtc_state *crtc_state,
 					    struct intel_connector *connector,
 					    bool respect_downstream_limits,
-					    enum intel_output_format sink_format)
+					    enum intel_output_format sink_format,
+					    bool enable_frl)
 {
 	const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
 
@@ -2295,7 +2307,7 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
 	crtc_state->sink_format = sink_format;
 	crtc_state->output_format = intel_hdmi_output_format(crtc_state);
 
-	return intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
+	return intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits, enable_frl);
 }
 
 static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
@@ -2312,7 +2324,8 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
 	if (drm_mode_is_420_only(info, adjusted_mode)) {
 		ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 						       respect_downstream_limits,
-						       INTEL_OUTPUT_FORMAT_YCBCR420);
+						       INTEL_OUTPUT_FORMAT_YCBCR420,
+						       false);
 
 		if (ret && !respect_downstream_limits) {
 			drm_dbg_kms(display->drm,
@@ -2320,17 +2333,20 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
 
 			ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 							       respect_downstream_limits,
-							       INTEL_OUTPUT_FORMAT_RGB);
+							       INTEL_OUTPUT_FORMAT_RGB,
+							       false);
 		}
 	} else {
 		ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 						       respect_downstream_limits,
-						       INTEL_OUTPUT_FORMAT_RGB);
+						       INTEL_OUTPUT_FORMAT_RGB,
+						       false);
 
 		if (ret && drm_mode_is_420_also(info, adjusted_mode))
 			ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 							       respect_downstream_limits,
-							       INTEL_OUTPUT_FORMAT_YCBCR420);
+							       INTEL_OUTPUT_FORMAT_YCBCR420,
+							       false);
 	}
 
 	return ret;
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 25/44] drm/i915/hdmi: Rename port clock limit to specify tmds clock
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (23 preceding siblings ...)
  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 ` 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
                   ` (19 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

The existing port clock limit function takes care of the TMDS mode of
transmission. Specify the port clock limit type explicitly as tmds.
This will pave way to add a separate port clock limit function for
FRL mode.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 8f0ee9282b61..fe5a092a1f0a 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1858,9 +1858,9 @@ static bool intel_hdmi_is_ycbcr420(const struct intel_crtc_state *crtc_state)
 	return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420;
 }
 
-static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
-				 bool respect_downstream_limits,
-				 bool has_hdmi_sink)
+static int hdmi_port_tmds_clock_limit(struct intel_hdmi *hdmi,
+				      bool respect_downstream_limits,
+				      bool has_hdmi_sink)
 {
 	struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base;
 	int max_tmds_clock = intel_hdmi_source_max_tmds_clock(encoder);
@@ -1893,8 +1893,8 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi,
 
 	if (clock < 25000)
 		return MODE_CLOCK_LOW;
-	if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits,
-					  has_hdmi_sink))
+	if (clock > hdmi_port_tmds_clock_limit(hdmi, respect_downstream_limits,
+					       has_hdmi_sink))
 		return MODE_CLOCK_HIGH;
 
 	/* GLK DPLL can't generate 446-480 MHz */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 26/44] drm/i915/cx0: Add helper to check if the FRL rate is valid
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (24 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 27/44] drm/i915/lt_phy: " Ankit Nautiyal
                   ` (18 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Introduce helper intel_cx0_phy_hdmi_frl_rate_valid() to check if the
given FRL rate is supported for the c10/20 Phys.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_cx0_phy.c | 23 ++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_cx0_phy.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index 452062417ce9..4391bc4cb48a 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -3868,3 +3868,26 @@ void intel_cx0pll_verify_plls(struct intel_display *display)
 	intel_cx0pll_verify_tables(display, xe3lpd_c20_dp_edp_tables);
 	intel_cx0pll_verify_tables(display, mtl_c20_hdmi_tables);
 }
+
+enum drm_mode_status
+intel_cx0_phy_hdmi_frl_rate_valid(struct intel_hdmi *hdmi, int clock_rate)
+{
+	struct intel_digital_port *dig_port = hdmi_to_dig_port(hdmi);
+	const struct intel_cx0pll_params *tables;
+	int i;
+
+	if (intel_encoder_is_c10phy(&dig_port->base))
+		tables = mtl_c10_hdmi_tables;
+	else
+		tables = mtl_c20_hdmi_tables;
+
+	for (i = 0; tables[i].name; i++) {
+		if (!intel_hdmi_is_frl(tables[i].clock_rate))
+			continue;
+
+		if (clock_rate == tables[i].clock_rate)
+			return MODE_OK;
+	}
+
+	return MODE_CLOCK_RANGE;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
index 95c20eb4b4b7..b7785bcebecb 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
@@ -84,5 +84,6 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder,
 void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
 			      const struct intel_crtc_state *crtc_state);
 void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder);
+enum drm_mode_status intel_cx0_phy_hdmi_frl_rate_valid(struct intel_hdmi *hdmi, int clock_rate);
 
 #endif /* __INTEL_CX0_PHY_H__ */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 27/44] drm/i915/lt_phy: Add helper to check if the FRL rate is valid
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (25 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 28/44] drm/i915/hdmi: Rename port clock valid to specify tmds clock Ankit Nautiyal
                   ` (17 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Introduce helper intel_lt_phy_hdmi_frl_rate_valid() to check if the
given FRL rate is supported for the LT Phy.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_lt_phy.c | 16 ++++++++++++++++
 drivers/gpu/drm/i915/display/intel_lt_phy.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index 2c1da689fe00..f7265d32915d 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -2652,3 +2652,19 @@ void intel_lt_phy_verify_plls(struct intel_display *display)
 	intel_lt_phy_pll_verify_tables(display, xe3plpd_lt_edp_tables);
 	intel_lt_phy_pll_verify_tables(display, xe3plpd_lt_hdmi_tables);
 }
+
+enum drm_mode_status intel_lt_phy_hdmi_frl_rate_valid(int clock_rate)
+{
+	const struct intel_lt_phy_pll_params *tables = xe3plpd_lt_hdmi_tables;
+	int i;
+
+	for (i = 0; tables[i].name; i++) {
+		if (!intel_hdmi_is_frl(tables[i].clock_rate))
+			continue;
+
+		if (clock_rate == tables[i].clock_rate)
+			return MODE_OK;
+	}
+
+	return MODE_CLOCK_RANGE;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h
index 16de39484779..20714ecd9f62 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h
@@ -49,5 +49,6 @@ void intel_xe3plpd_pll_enable(struct intel_encoder *encoder,
 			      const struct intel_dpll_hw_state *dpll_hw_state);
 void intel_xe3plpd_pll_disable(struct intel_encoder *encoder);
 void intel_lt_phy_verify_plls(struct intel_display *display);
+enum drm_mode_status intel_lt_phy_hdmi_frl_rate_valid(int clock_rate);
 
 #endif /* __INTEL_LT_PHY_H__ */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 28/44] drm/i915/hdmi: Rename port clock valid to specify tmds clock
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (26 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 27/44] drm/i915/lt_phy: " Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 29/44] drm/i915/hdmi: Add FRL port and mode clock valid Ankit Nautiyal
                   ` (16 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

The existing port clock valid function takes care of the TMDS mode of
transmission. Specify the port clock valid type explicitly as tmds.
This will pave way to add a separate port clock valid function for
FRL mode.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index fe5a092a1f0a..5a3241c054f7 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1884,9 +1884,9 @@ static int hdmi_port_tmds_clock_limit(struct intel_hdmi *hdmi,
 }
 
 static enum drm_mode_status
-hdmi_port_clock_valid(struct intel_hdmi *hdmi,
-		      int clock, bool respect_downstream_limits,
-		      bool has_hdmi_sink)
+hdmi_port_tmds_clock_valid(struct intel_hdmi *hdmi,
+			   int clock, bool respect_downstream_limits,
+			   bool has_hdmi_sink)
 {
 	struct intel_display *display = to_intel_display(hdmi);
 	struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base;
@@ -2010,7 +2010,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 						  sink_format))
 			continue;
 
-		status = hdmi_port_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink);
+		status = hdmi_port_tmds_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink);
 		if (status == MODE_OK)
 			return MODE_OK;
 	}
@@ -2186,9 +2186,9 @@ static int intel_hdmi_compute_bpc(struct intel_encoder *encoder,
 						       crtc_state->sink_format);
 
 		if (hdmi_bpc_possible(crtc_state, bpc) &&
-		    hdmi_port_clock_valid(intel_hdmi, tmds_clock,
-					  respect_downstream_limits,
-					  crtc_state->has_hdmi_sink) == MODE_OK)
+		    hdmi_port_tmds_clock_valid(intel_hdmi, tmds_clock,
+					       respect_downstream_limits,
+					       crtc_state->has_hdmi_sink) == MODE_OK)
 			return bpc;
 	}
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 29/44] drm/i915/hdmi: Add FRL port and mode clock valid
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (27 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 30/44] drm/i915/hdmi_frl_dfm_regs: Define DFM registers Ankit Nautiyal
                   ` (15 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Add the clock valid checks for the HDMI FRL mode of transmission.

Introduce hdmi_port_frl_clock_valid() which validates the FRL link
rate against the maximum FRL rate and the source PHY (c10/c20 or LT),
and a common hdmi_port_clock_valid() wrapper that dispatches to the
TMDS or FRL helper based on frl_mode. Similarly add intel_hdmi_frl_clock()
and a common intel_hdmi_clock() wrapper to compute the required clock
for the selected mode of transmission.

Wire these into intel_hdmi_mode_clock_valid() via the common wrappers.
FRL mode is not enabled yet, so the callers pass frl_mode as false and
the existing TMDS behaviour is unchanged. A subsequent change will
compute frl_mode and enable FRL based validation.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 100 +++++++++++++++++++++-
 drivers/gpu/drm/i915/display/intel_hdmi.h |   4 +-
 2 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 5a3241c054f7..7170546f4779 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -64,6 +64,7 @@
 #include "intel_hdmi.h"
 #include "intel_link_bw.h"
 #include "intel_lspcon.h"
+#include "intel_lt_phy.h"
 #include "intel_panel.h"
 #include "intel_pfit.h"
 #include "intel_snps_phy.h"
@@ -1921,6 +1922,78 @@ hdmi_port_tmds_clock_valid(struct intel_hdmi *hdmi,
 	return MODE_OK;
 }
 
+/*
+ * Returns the Fixed rate in 10 Kbps per lane required to support given
+ * pixel rate.
+ * Returns 0 for pixel rate demanding > 12 Gbps
+ */
+static int intel_hdmi_frl_required_bitrate(int pixel_rate_10kbps)
+{
+	/*
+	 * 3 lane configurations:
+	 * 3 Gbps * 3 = 9 Gbps; 6 Gbps * 3 = 18 Gbps.
+	 *
+	 * 4 lane configurations:
+	 * 6 Gbps * 4 = 24 Gbps; 8 Gbps * 4 = 32 Gbp;
+	 * 10 Gbps * 4 = 40 Gbps; 12 Gbps * 4 = 48 Gbps.
+	 */
+	if (pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(9))
+		return FRL_GBPS_TO_10KBPS(3);
+
+	if (pixel_rate_10kbps > FRL_GBPS_TO_10KBPS(9) &&
+	    pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(18))
+		return FRL_GBPS_TO_10KBPS(6);
+
+	if (pixel_rate_10kbps > FRL_GBPS_TO_10KBPS(18) &&
+	    pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(24))
+		return FRL_GBPS_TO_10KBPS(6);
+
+	if (pixel_rate_10kbps > FRL_GBPS_TO_10KBPS(24) &&
+	    pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(32))
+		return FRL_GBPS_TO_10KBPS(8);
+
+	if (pixel_rate_10kbps > FRL_GBPS_TO_10KBPS(32) &&
+	    pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(40))
+		return FRL_GBPS_TO_10KBPS(10);
+
+	if (pixel_rate_10kbps > FRL_GBPS_TO_10KBPS(40) &&
+	    pixel_rate_10kbps <= FRL_GBPS_TO_10KBPS(48))
+		return FRL_GBPS_TO_10KBPS(12);
+
+	/*
+	 * pixel rate more than 48 Gbps rate, means more than
+	 * 12 Gbps x 4 lanes. Such a rate not possible with FRL.
+	 */
+	return 0;
+}
+
+static enum drm_mode_status
+hdmi_port_frl_clock_valid(struct intel_hdmi *hdmi, int clock)
+{
+	struct intel_display *display = to_intel_display(hdmi);
+
+	if (DISPLAY_VER(display) >= 35)
+		return intel_lt_phy_hdmi_frl_rate_valid(clock);
+
+	if (DISPLAY_VER(display) >= 14)
+		return intel_cx0_phy_hdmi_frl_rate_valid(hdmi, clock);
+
+	return MODE_OK;
+}
+
+static enum drm_mode_status
+hdmi_port_clock_valid(struct intel_hdmi *hdmi,
+		      int clock, bool respect_downstream_limits,
+		      bool has_hdmi_sink, bool frl_mode)
+{
+	if (frl_mode)
+		return hdmi_port_frl_clock_valid(hdmi, clock);
+
+	return hdmi_port_tmds_clock_valid(hdmi, clock,
+					  respect_downstream_limits,
+					  has_hdmi_sink);
+}
+
 int intel_hdmi_tmds_clock(int clock, int bpc,
 			  enum intel_output_format sink_format)
 {
@@ -1984,6 +2057,29 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
 	}
 }
 
+static
+int intel_hdmi_frl_clock(int clock, int bpc, enum intel_output_format sink_format)
+{
+	int pixel_rate_kbps;
+
+	if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+		clock /= 2;
+
+	pixel_rate_kbps = clock * bpc * 3;
+
+	/* find the closest frl bit rate */
+	return intel_hdmi_frl_required_bitrate(pixel_rate_kbps / 10);
+}
+
+static
+int intel_hdmi_clock(int clock, int bpc, enum intel_output_format sink_format, bool frl_mode)
+{
+	if (frl_mode)
+		return intel_hdmi_frl_clock(clock, bpc, sink_format);
+
+	return intel_hdmi_tmds_clock(clock, bpc, sink_format);
+}
+
 static enum drm_mode_status
 intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 			    bool has_hdmi_sink,
@@ -2001,7 +2097,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 	 * least one color depth is accepted.
 	 */
 	for (bpc = 12; bpc >= 8; bpc -= 2) {
-		int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, sink_format);
+		int hdmi_clock = intel_hdmi_clock(clock, bpc, sink_format, false);
 
 		if (!intel_hdmi_source_bpc_possible(display, bpc))
 			continue;
@@ -2010,7 +2106,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 						  sink_format))
 			continue;
 
-		status = hdmi_port_tmds_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink);
+		status = hdmi_port_clock_valid(hdmi, hdmi_clock, true, has_hdmi_sink, false);
 		if (status == MODE_OK)
 			return MODE_OK;
 	}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 5baa38d326e5..0e78e700ebf9 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -80,8 +80,10 @@ void hsw_read_infoframe(struct intel_encoder *encoder,
 			void *frame, ssize_t len);
 void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state,
 					   struct drm_connector *_connector);
-
 int intel_hdmi_sink_max_frl_rate(struct drm_connector *connector);
 int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector);
 
+/* FRL rate per lane (Gbps) -> PHY PLL table units (10 kbps) */
+#define FRL_GBPS_TO_10KBPS(rate)	((rate) * 100000)
+
 #endif /* __INTEL_HDMI_H__ */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 30/44] drm/i915/hdmi_frl_dfm_regs: Define DFM registers
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (28 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 31/44] drm/i915/hdmi_frl_dfm: Define frl_dfm structure Ankit Nautiyal
                   ` (14 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Add defines for HDMI FRL dataflow metering registers
to take care of DFM values.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../i915/display/intel_hdmi_frl_dfm_regs.h    | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm_regs.h

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm_regs.h b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm_regs.h
new file mode 100644
index 000000000000..bb5cb76b3806
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm_regs.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_HDMI_FRL_DFM_REGS_H__
+#define __INTEL_HDMI_FRL_DFM_REGS_H__
+
+#include "intel_display_reg_defs.h"
+
+#define _TRANS_HDMI_FRL_DFMRDCTL_A			0x600bc
+#define TRANS_HDMI_FRL_DFMRDCTL(dev_priv, trans)	_MMIO_TRANS2(dev_priv, \
+								     trans, \
+								     _TRANS_HDMI_FRL_DFMRDCTL_A)
+#define   TB_DIFF_MAX_OFFSET_MASK			REG_GENMASK(8, 0)
+#define   TB_DIFF_MAX_OFFSET(val)			REG_FIELD_PREP(TB_DIFF_MAX_OFFSET_MASK, val)
+
+#define _TRANS_HDMI_FRL_DFMWRCTL_A			0x600c0
+#define TRANS_HDMI_FRL_DFMWRCTL(dev_priv, trans)	_MMIO_TRANS2(dev_priv, \
+								     trans, \
+								     _TRANS_HDMI_FRL_DFMWRCTL_A)
+#define  TB_ACTUAL_OFFSET_MASK				REG_GENMASK(8, 0)
+#define  TB_ACTUAL_OFFSET(val)				REG_FIELD_PREP(TB_ACTUAL_OFFSET_MASK, val)
+
+#define _TRANS_HDMI_FRL_DFMTHRSH_A			0x600c4
+#define TRANS_HDMI_FRL_DFMTHRSH(dev_priv, trans)	_MMIO_TRANS2(dev_priv, \
+								     trans, \
+								     _TRANS_HDMI_FRL_DFMTHRSH_A)
+#define  RUN_LEN_THRESHOLD_MASK				REG_GENMASK(31, 24)
+#define  RUN_LEN_THRESHOLD(val)				REG_FIELD_PREP(RUN_LEN_THRESHOLD_MASK, val)
+#define  TB_MAX_THRESHOLD_MASK				REG_GENMASK(21, 12)
+#define  TB_MAX_THRESHOLD(val)				REG_FIELD_PREP(TB_MAX_THRESHOLD_MASK, val)
+#define  TB_MIN_THESHOLD_MASK				REG_GENMASK(9, 0)
+#define  TB_MIN_THESHOLD(val)				REG_FIELD_PREP(TB_MIN_THESHOLD_MASK, val)
+
+#endif /* __INTEL_HDMI_FRL_DFM_REGS_H__ */
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 31/44] drm/i915/hdmi_frl_dfm: Define frl_dfm structure
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (29 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 30/44] drm/i915/hdmi_frl_dfm_regs: Define DFM registers Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 32/44] drm/i915/hdmi_frl_dfm: Add non dsc frl capacity computation helpers Ankit Nautiyal
                   ` (13 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Define frl_dfm structure to hold frl characteristics
needed for frl capacity computation in order to
meet the data flow metering requirement.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h | 113 ++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
new file mode 100644
index 000000000000..c619073eef9b
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright © 2022 Intel Corp
+ */
+
+#ifndef __INTEL_HDMI_FRL_DFM_H__
+#define __INTEL_HDMI_FRL_DFM_H__
+
+#include <linux/types.h>
+
+/* All the input config needed to compute DFM requirements */
+struct intel_hdmi_frl_dfm_input_config {
+	/*
+	 * Pixel clock rate kHz, when FVA is
+	 * enabled this rate is the rate after adjustment
+	 */
+	u32 pixel_clock_nominal_khz;
+
+	/* active pixels per line */
+	u32 hactive;
+
+	/* Blanking pixels per line */
+	u32 hblank;
+
+	/* Bits per component */
+	u32 bpc;
+
+	/* Pixel encoding */
+	u32 color_format;
+
+	/* FRL bit rate in kbps */
+	u32 bit_rate_kbps;
+
+	/* FRL lanes */
+	u32 lanes;
+
+	/* Number of audio channels */
+	u32 audio_channels;
+
+	/* Audio rate in Hz */
+	u32 audio_hz;
+
+	/* Selected bpp target value */
+	u32 target_bpp_16;
+
+	/*
+	 * Number of horizontal pixels in a slice.
+	 * Equivalent to PPS parameter slice_width
+	 */
+	u32 slice_width;
+};
+
+/* Computed dfm parameters for FRL */
+struct intel_hdmi_frl_dfm_params {
+	/*
+	 * Link overhead in percentage
+	 * multiplied by 1000 (efficiency multiplier)
+	 */
+	u32 overhead_max;
+
+	/* Maximum pixel rate in kHz */
+	u32 pixel_clock_max_khz;
+
+	/* Minimum video line period in nano sec */
+	u32 line_time_ns;
+
+	/* worst case slow frl character rate in kbps */
+	u32 char_rate_min_kbps;
+
+	/* minimum total frl charecters per line period */
+	u32 cfrl_line;
+
+	/* Average tribyte rate in khz */
+	u32 ftb_avg_k;
+
+	/* Audio characteristics */
+
+	/*  number of audio packets needed during hblank */
+	u32 num_audio_pkts_line;
+
+	/*
+	 *  Minimum required hblank assuming no control period
+	 *  RC compression
+	 */
+	u32 hblank_audio_min;
+
+	/* Number of tribytes required to carry active video */
+	u32 tb_active;
+
+	/* Total available tribytes during the blanking period */
+	u32 tb_blank;
+
+	/*
+	 * Number of tribytes required to be transmitted during
+	 * the hblank period
+	 */
+	u32 tb_borrowed;
+
+	/* DSC frl characteristics */
+
+	/* Tribytes required to carry the target bpp */
+	u32 hcactive_target;
+
+	/* tribytes available during blanking with target bpp */
+	u32 hcblank_target;
+};
+
+/* FRL DFM structure to hold data involved in DFM computation */
+struct intel_hdmi_frl_dfm {
+	struct intel_hdmi_frl_dfm_input_config config;
+	struct intel_hdmi_frl_dfm_params params;
+};
+
+#endif
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 32/44] drm/i915/hdmi_frl_dfm: Add non dsc frl capacity computation helpers
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (30 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 31/44] drm/i915/hdmi_frl_dfm: Define frl_dfm structure Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 33/44] drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC Ankit Nautiyal
                   ` (12 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Add helper functions for computing non dsc frl
link characteristics

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 33/44] drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (31 preceding siblings ...)
  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
  2026-08-07  4:14 ` [PATCH 34/44] drm/i915/hdmi: Add helper to write FRL CFG register Ankit Nautiyal
                   ` (11 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

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


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 34/44] drm/i915/hdmi: Add helper to write FRL CFG register
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (32 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 33/44] drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC Ankit Nautiyal
@ 2026-08-07  4:14 ` 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
                   ` (10 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Introduce helpers to write FRL CFG refister bits.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 16 ++++++++++++++++
 drivers/gpu/drm/i915/display/intel_hdmi.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 7170546f4779..4d547c27914c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -3992,3 +3992,19 @@ void intel_hdmi_disable_frl(struct intel_encoder *encoder,
 
 	intel_hdmi_reset_frl_config(intel_hdmi);
 }
+
+void intel_hdmi_frl_cfg_write(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_trans = crtc_state->cpu_transcoder;
+	u32 val;
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	val = TRANS_HDMI_R_B_SCHED_ENABLE(crtc_state->frl.rsrc_sched_en);
+	val |= TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH(crtc_state->frl.active_char_buf_threshold);
+	val |= TRANS_HDMI_MIN_BLANK_CHAR(TRANS_HDMI_MIN_BLANK_CHAR_VAL);
+
+	intel_de_rmw(display, TRANS_HDMI_FRL_CFG(display, cpu_trans), 0, val);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 0e78e700ebf9..41d0a850ec76 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -82,6 +82,7 @@ void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_s
 					   struct drm_connector *_connector);
 int intel_hdmi_sink_max_frl_rate(struct drm_connector *connector);
 int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector);
+void intel_hdmi_frl_cfg_write(const struct intel_crtc_state *crtc_state);
 
 /* FRL rate per lane (Gbps) -> PHY PLL table units (10 kbps) */
 #define FRL_GBPS_TO_10KBPS(rate)	((rate) * 100000)
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 35/44] drm/i915/hdmi_frl_dfm: Add helpers to read/write FRL DFM registers
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (33 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 36/44] drm/i915/hdmi_frl_dfm: Add function to compute FRL DFM config Ankit Nautiyal
                   ` (9 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Introduce helpers to read/write FRL Data Flow Metering registers.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 42 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h |  5 +++
 2 files changed, 47 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 56ade6009983..51a09c05bef3 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c
@@ -7,7 +7,12 @@
 
 #include <drm/drm_connector.h>
 
+#include "intel_de.h"
+#include "intel_display_driver.h"
+#include "intel_display_regs.h"
+#include "intel_display_types.h"
 #include "intel_hdmi_frl_dfm.h"
+#include "intel_hdmi_frl_dfm_regs.h"
 
 /* DFM constraints and tolerance values */
 #define TB_BORROWED_MAX			400
@@ -702,3 +707,40 @@ bool intel_hdmi_frl_dfm_dsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm)
 
 	return true;
 }
+
+void intel_hdmi_frl_dfm_write(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_trans = crtc_state->cpu_transcoder;
+	i915_reg_t reg;
+	u32 val;
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	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);
+
+	reg = TRANS_HDMI_FRL_DFMTHRSH(display, cpu_trans);
+	val = TB_MIN_THESHOLD(crtc_state->frl.tb_threshold_min);
+	intel_de_rmw(display, reg, TB_MIN_THESHOLD_MASK, val);
+}
+
+void intel_hdmi_frl_dfm_read(struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_trans = crtc_state->cpu_transcoder;
+	u32 val;
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	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);
+
+	val = intel_de_read(display, TRANS_HDMI_FRL_DFMTHRSH(display, cpu_trans));
+	crtc_state->frl.tb_threshold_min =
+		REG_FIELD_GET(TB_MIN_THESHOLD_MASK, val);
+}
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 70a66679bdbc..1bfc70067518 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h
@@ -7,6 +7,8 @@
 
 #include <linux/types.h>
 
+struct intel_crtc_state;
+
 /* All the input config needed to compute DFM requirements */
 struct intel_hdmi_frl_dfm_input_config {
 	/*
@@ -115,4 +117,7 @@ bool intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_df
 bool
 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);
+
 #endif
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 36/44] drm/i915/hdmi_frl_dfm: Add function to compute FRL DFM config
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (34 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 37/44] drm/i915/hdmi: Add FRL clock computation based on DFM Ankit Nautiyal
                   ` (8 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

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 <ankit.k.nautiyal@intel.com>
Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 37/44] drm/i915/hdmi: Add FRL clock computation based on DFM
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (35 preceding siblings ...)
  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 ` 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
                   ` (7 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Compute the FRL port clock for a mode using the DFM helper.
Starting with the lowest FRL rate that meets the DFM requirements, check
if the mode can be supported with FRL and derive the port clock from the
selected FRL rate and lane count.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 61 ++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 4d547c27914c..0977c7011dd3 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -62,6 +62,7 @@
 #include "intel_hdcp_regs.h"
 #include "intel_hdcp_shim.h"
 #include "intel_hdmi.h"
+#include "intel_hdmi_frl_dfm.h"
 #include "intel_link_bw.h"
 #include "intel_lspcon.h"
 #include "intel_lt_phy.h"
@@ -2325,13 +2326,71 @@ static int intel_hdmi_compute_tmds_clock(struct intel_encoder *encoder,
 	return 0;
 }
 
+static int
+intel_hdmi_compute_frl_config(struct intel_encoder *encoder,
+			      struct intel_crtc_state *crtc_state)
+{
+	int ret;
+
+	ret = intel_hdmi_frl_dfm_compute_config(encoder, crtc_state);
+	if (ret) {
+		memset(&crtc_state->frl, 0, sizeof(crtc_state->frl));
+		return ret;
+	}
+
+	/*
+	 * TODO
+	 * 1. Calculate condition for Reseource based scheduling enable.
+	 * Disabling resource based scheduling for now.
+	 * 2. Active Character buffer threshold depends on cd clock bw.
+	 * Setting default value of 0.
+	 */
+	crtc_state->frl.rsrc_sched_en = false;
+	crtc_state->frl.active_char_buf_threshold = 0;
+
+	return 0;
+}
+
+static int
+intel_hdmi_compute_frl_clock(struct intel_encoder *encoder,
+			     struct intel_crtc_state *crtc_state)
+{
+	struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder);
+	int max_bpc = max(crtc_state->pipe_bpp / 3, 8);
+	int port_clock;
+	int bpc;
+
+	for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
+		int ret;
+
+		if (!hdmi_bpc_possible(crtc_state, bpc))
+			continue;
+
+		crtc_state->pipe_bpp = bpc * 3;
+
+		ret = intel_hdmi_compute_frl_config(encoder, crtc_state);
+		if (ret)
+			continue;
+
+		/* Port clock for FRL rates is bitrate in 10Kbps */
+		port_clock = FRL_GBPS_TO_10KBPS(crtc_state->frl.required_rate);
+
+		if (hdmi_port_frl_clock_valid(hdmi, port_clock) == MODE_OK) {
+			crtc_state->port_clock = port_clock;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static int intel_hdmi_compute_clock(struct intel_encoder *encoder,
 				    struct intel_crtc_state *crtc_state,
 				    bool respect_downstream_limits,
 				    bool enable_frl)
 {
 	if (enable_frl)
-		return -EINVAL;
+		return intel_hdmi_compute_frl_clock(encoder, crtc_state);
 
 	return intel_hdmi_compute_tmds_clock(encoder, crtc_state, respect_downstream_limits);
 }
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 38/44] drm/i915/hdmi: Add support for sending uevent to user for FRL training failure
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (36 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 39/44] drm/i915/ddi: Wire FRL into the HDMI DDI enable/disable path Ankit Nautiyal
                   ` (6 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

In case of HDMI FRL training failure for a given mode, the user
should be sent a uevent signalling Link failure.

Add support for sending uevent to userspace in case of link training
failure.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 32 +++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 0977c7011dd3..e30adda6dac2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -71,6 +71,8 @@
 #include "intel_snps_phy.h"
 #include "intel_vrr.h"
 
+#define HAS_HDMI_FRL(__display)		(DISPLAY_VER((__display)) >= 14)
+
 bool intel_hdmi_is_frl(u32 clock)
 {
 	static const u32 rates[] = { 300000, 600000, 800000, 1000000, 1200000 };
@@ -3363,6 +3365,31 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
 	}
 }
 
+/* Common code with DP, need to put in a common place */
+static void intel_hdmi_modeset_retry_work_fn(struct work_struct *work)
+{
+	struct intel_connector *intel_connector;
+	struct drm_connector *connector;
+
+	intel_connector = container_of(work, typeof(*intel_connector),
+				       modeset_retry_work);
+	connector = &intel_connector->base;
+	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
+		      connector->name);
+
+	/* Grab the locks before changing connector property*/
+	mutex_lock(&connector->dev->mode_config.mutex);
+	/*
+	 * Set connector link status to BAD and send a Uevent to notify
+	 * userspace to do a modeset.
+	 */
+	drm_connector_set_link_status_property(connector,
+					       DRM_MODE_LINK_STATUS_BAD);
+	mutex_unlock(&connector->dev->mode_config.mutex);
+	/* Send Hotplug uevent so userspace can reprobe */
+	drm_kms_helper_hotplug_event(connector->dev);
+}
+
 bool intel_hdmi_init_connector(struct intel_digital_port *dig_port,
 			       struct intel_connector *intel_connector)
 {
@@ -3436,6 +3463,11 @@ bool intel_hdmi_init_connector(struct intel_digital_port *dig_port,
 	if (!intel_hdmi->cec_notifier)
 		drm_dbg_kms(display->drm, "CEC notifier get failed\n");
 
+	/* Initialize the work for modeset in case of link train failure */
+	if (HAS_HDMI_FRL(display))
+		INIT_WORK(&intel_connector->modeset_retry_work,
+			  intel_hdmi_modeset_retry_work_fn);
+
 	return true;
 }
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 39/44] drm/i915/ddi: Wire FRL into the HDMI DDI enable/disable path
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (37 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 40/44] drm/i915/hdmi: Add read out for FRL state Ankit Nautiyal
                   ` (5 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Enable HDMI FRL in the DDI enable and disable sequences for MTL+:

Enable path (intel_ddi_enable_hdmi):
-Prepare for FRL mode before enabling D2D link.
-After the DDI buffer is enabled, run FRL link training. If FRL link
training fails, disable FRL and notify userspace. On success, write
DFM registers and enable the transcoder.

Disable path (intel_ddi_post_disable_hdmi):
Call intel_hdmi_disable_frl() after the DDI buffer is disabled to perform
LTS:L teardown and clear the FRL function registers.

Bspec:65750
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index d1a60cdf55fa..6ee2c3119c9b 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -70,6 +70,7 @@
 #include "intel_gmbus.h"
 #include "intel_hdcp.h"
 #include "intel_hdmi.h"
+#include "intel_hdmi_frl_dfm.h"
 #include "intel_hotplug.h"
 #include "intel_hti.h"
 #include "intel_lspcon.h"
@@ -3217,6 +3218,8 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state,
 		intel_ddi_disable_transcoder_clock(old_crtc_state);
 
 	intel_ddi_buf_disable(encoder, old_crtc_state);
+	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
+		intel_hdmi_disable_frl(encoder, old_crtc_state);
 
 	if (DISPLAY_VER(display) >= 12)
 		intel_ddi_disable_transcoder_clock(old_crtc_state);
@@ -3471,6 +3474,9 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 	struct drm_connector *connector = conn_state->connector;
+	struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
+	struct intel_connector *intel_connector =
+		intel_hdmi->attached_connector;
 	enum port port = encoder->port;
 	u32 buf_ctl = 0;
 
@@ -3491,6 +3497,9 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 	if (has_buf_trans_select(display))
 		hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state);
 
+	if (DISPLAY_VER(display) >= 14 && crtc_state->frl.enable)
+		intel_hdmi_prepare_for_frl_mode(crtc_state);
+
 	/* e. Enable D2D Link for C10/C20 Phy */
 	mtl_ddi_enable_d2d(encoder);
 
@@ -3582,8 +3591,18 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
 
 	intel_ddi_buf_enable(encoder, buf_ctl);
 
-	if (DISPLAY_VER(display) >= 14)
+	if (DISPLAY_VER(display) >= 14) {
+		if (crtc_state->frl.enable &&
+		    intel_hdmi_start_frl(encoder, crtc_state) < 0) {
+			intel_hdmi_disable_frl(encoder, crtc_state);
+			schedule_work(&intel_connector->modeset_retry_work);
+
+			return;
+		}
+		intel_hdmi_frl_cfg_write(crtc_state);
+		intel_hdmi_frl_dfm_write(crtc_state);
 		intel_ddi_enable_transcoder_and_vblank(state, encoder, crtc_state);
+	}
 
 	intel_hdmi_poll_for_scrambling_enable(crtc_state, connector);
 }
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 40/44] drm/i915/hdmi: Add read out for FRL state
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (38 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 41/44] drm/i915/hdmi_frl_dfm: Handle FRL Link M/N Ankit Nautiyal
                   ` (4 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Read out the FRL configuration and Data Flow Metering registers and
fill the FRL members in crtc_state.

In subsequent changes these are added to the state checker and compared
bwteen two crtc_states in intel_pipe_config_compare().

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c  |  3 ++
 drivers/gpu/drm/i915/display/intel_hdmi.c | 35 +++++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_hdmi.h |  1 +
 3 files changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 6ee2c3119c9b..fc465683782a 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4281,6 +4281,9 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,
 	intel_read_dp_sdp(encoder, pipe_config, DP_SDP_ADAPTIVE_SYNC);
 
 	intel_audio_codec_get_config(encoder, pipe_config);
+
+	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
+		intel_hdmi_frl_get_config(pipe_config);
 }
 
 void intel_ddi_get_clock(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index e30adda6dac2..05d3bb40ca30 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -4099,3 +4099,38 @@ void intel_hdmi_frl_cfg_write(const struct intel_crtc_state *crtc_state)
 
 	intel_de_rmw(display, TRANS_HDMI_FRL_CFG(display, cpu_trans), 0, val);
 }
+
+static void intel_hdmi_frl_cfg_read(struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+	enum transcoder cpu_trans = crtc_state->cpu_transcoder;
+	u32 val;
+
+	val = intel_de_read(display, TRANS_HDMI_FRL_CFG(display, cpu_trans));
+
+	if (val & TRANS_HDMI_FRL_ENABLE)
+		crtc_state->frl.enable = true;
+
+	crtc_state->frl.rsrc_sched_en =
+		REG_FIELD_GET(TRANS_HDMI_R_B_SCHED_ENABLE_MASK, val);
+	crtc_state->frl.active_char_buf_threshold =
+		REG_FIELD_GET(TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH_MASK, val);
+}
+
+void intel_hdmi_frl_get_config(struct intel_crtc_state *crtc_state)
+{
+	struct intel_display *display = to_intel_display(crtc_state);
+
+	if (!HAS_HDMI_FRL(display))
+		return;
+
+	intel_hdmi_frl_cfg_read(crtc_state);
+
+	if (!crtc_state->frl.enable)
+		return;
+
+	crtc_state->frl.required_rate = crtc_state->port_clock / 100000;
+	crtc_state->frl.required_lanes = crtc_state->lane_count;
+
+	intel_hdmi_frl_dfm_read(crtc_state);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 41d0a850ec76..cf5ccd308ce6 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -83,6 +83,7 @@ void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_s
 int intel_hdmi_sink_max_frl_rate(struct drm_connector *connector);
 int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector);
 void intel_hdmi_frl_cfg_write(const struct intel_crtc_state *crtc_state);
+void intel_hdmi_frl_get_config(struct intel_crtc_state *crtc_state);
 
 /* FRL rate per lane (Gbps) -> PHY PLL table units (10 kbps) */
 #define FRL_GBPS_TO_10KBPS(rate)	((rate) * 100000)
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 41/44] drm/i915/hdmi_frl_dfm: Handle FRL Link M/N
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (39 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 40/44] drm/i915/hdmi: Add read out for FRL state Ankit Nautiyal
@ 2026-08-07  4:14 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 42/44] drm/i915/display: Add FRL members to the state checker Ankit Nautiyal
                   ` (3 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

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 <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 42/44] drm/i915/display: Add FRL members to the state checker
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (40 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07  4:14 ` [PATCH 43/44] drm/i915/hdmi: Compute output format for HDMI FRL mode Ankit Nautiyal
                   ` (2 subsequent siblings)
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

Plug in the FRL members to the state checker.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 829d7a411dcc..ca429ea385c6 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -5555,6 +5555,15 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
 
 	PIPE_CONF_CHECK_I(set_context_latency);
 
+	PIPE_CONF_CHECK_BOOL(frl.enable);
+	PIPE_CONF_CHECK_BOOL(frl.rsrc_sched_en);
+	PIPE_CONF_CHECK_I(frl.required_lanes);
+	PIPE_CONF_CHECK_I(frl.tb_borrowed);
+	PIPE_CONF_CHECK_I(frl.tb_actual);
+	PIPE_CONF_CHECK_I(frl.active_char_buf_threshold);
+	PIPE_CONF_CHECK_I(frl.link_m);
+	PIPE_CONF_CHECK_I(frl.link_n);
+
 #undef PIPE_CONF_CHECK_X
 #undef PIPE_CONF_CHECK_I
 #undef PIPE_CONF_CHECK_LLI
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 43/44] drm/i915/hdmi: Compute output format for HDMI FRL mode
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (41 preceding siblings ...)
  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 ` 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
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

If the source and sink support FRL, then compute output format
that can support HDMI FRL mode. This in turn calculates the FRL
configuration, clocks etc required to support a video mode with
FRL transmission.

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 66 +++++++++++++++++------
 1 file changed, 50 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 05d3bb40ca30..1773b2096e9f 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2467,10 +2467,11 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
 	return intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits, enable_frl);
 }
 
-static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
-				      struct intel_crtc_state *crtc_state,
-				      const struct drm_connector_state *conn_state,
-				      bool respect_downstream_limits)
+static int _intel_hdmi_compute_formats(struct intel_encoder *encoder,
+				       struct intel_crtc_state *crtc_state,
+				       const struct drm_connector_state *conn_state,
+				       bool respect_downstream_limits,
+				       bool enable_frl)
 {
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
@@ -2482,7 +2483,7 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
 		ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 						       respect_downstream_limits,
 						       INTEL_OUTPUT_FORMAT_YCBCR420,
-						       false);
+						       enable_frl);
 
 		if (ret && !respect_downstream_limits) {
 			drm_dbg_kms(display->drm,
@@ -2491,19 +2492,19 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
 			ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 							       respect_downstream_limits,
 							       INTEL_OUTPUT_FORMAT_RGB,
-							       false);
+							       enable_frl);
 		}
 	} else {
 		ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 						       respect_downstream_limits,
 						       INTEL_OUTPUT_FORMAT_RGB,
-						       false);
+						       enable_frl);
 
 		if (ret && drm_mode_is_420_also(info, adjusted_mode))
 			ret = intel_hdmi_compute_output_format(encoder, crtc_state, connector,
 							       respect_downstream_limits,
 							       INTEL_OUTPUT_FORMAT_YCBCR420,
-							       false);
+							       enable_frl);
 	}
 
 	return ret;
@@ -2544,6 +2545,26 @@ bool intel_hdmi_compute_has_hdmi_sink(struct intel_encoder *encoder,
 		!intel_hdmi_is_cloned(crtc_state);
 }
 
+static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
+				      struct intel_crtc_state *crtc_state,
+				      const struct drm_connector_state *conn_state,
+				      bool enable_frl)
+{
+	int ret;
+
+	/*
+	 * Try to respect downstream TMDS clock limits first, if
+	 * that fails assume the user might know something we don't.
+	 */
+	ret = _intel_hdmi_compute_formats(encoder, crtc_state,
+					  conn_state, true, enable_frl);
+	if (ret)
+		ret = _intel_hdmi_compute_formats(encoder, crtc_state,
+						  conn_state, false, enable_frl);
+
+	return ret;
+}
+
 int intel_hdmi_compute_config(struct intel_encoder *encoder,
 			      struct intel_crtc_state *pipe_config,
 			      struct drm_connector_state *conn_state)
@@ -2552,6 +2573,9 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
 	struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
 	struct drm_scdc *scdc = &connector->base.display_info.hdmi.scdc;
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	bool enable_frl = false;
+	int lane_count = 4;
 	int ret;
 
 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -2576,13 +2600,23 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
 		intel_hdmi_has_audio(encoder, pipe_config, conn_state) &&
 		intel_audio_compute_config(encoder, pipe_config, conn_state);
 
-	/*
-	 * Try to respect downstream TMDS clock limits first, if
-	 * that fails assume the user might know something we don't.
-	 */
-	ret = intel_hdmi_compute_formats(encoder, pipe_config, conn_state, true);
-	if (ret)
-		ret = intel_hdmi_compute_formats(encoder, pipe_config, conn_state, false);
+	if (HAS_HDMI_FRL(display) &&
+	    intel_bios_hdmi_max_frl_rate(encoder) &&
+	    intel_hdmi->has_sink_hdmi_21)
+		enable_frl = true;
+
+	ret = intel_hdmi_compute_formats(encoder, pipe_config, conn_state, false);
+
+	if (ret && enable_frl) {
+		ret = intel_hdmi_compute_formats(encoder, pipe_config, conn_state, true);
+		drm_dbg_kms(display->drm,
+			    "Enabling FRL mode with lanes = %d rate = %d\n",
+			    pipe_config->frl.required_lanes,
+			    pipe_config->frl.required_rate);
+		pipe_config->frl.enable = true;
+		lane_count = pipe_config->frl.required_lanes;
+	}
+
 	if (ret) {
 		drm_dbg_kms(display->drm,
 			    "unsupported HDMI clock (%d kHz), rejecting mode\n",
@@ -2601,7 +2635,7 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
 		adjusted_mode->picture_aspect_ratio =
 			conn_state->picture_aspect_ratio;
 
-	pipe_config->lane_count = 4;
+	pipe_config->lane_count = lane_count;
 
 	if (scdc->scrambling.supported && source_supports_scrambling(encoder) &&
 	    !pipe_config->frl.enable) {
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 44/44] drm/i915/hdmi: Enable FRL based mode clock valid
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (42 preceding siblings ...)
  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 ` Ankit Nautiyal
  2026-08-07 15:32 ` ✓ i915.CI.BAT: success for Enable HDMI FRL for MTL+ Patchwork
  44 siblings, 0 replies; 48+ messages in thread
From: Ankit Nautiyal @ 2026-08-07  4:14 UTC (permalink / raw)
  To: intel-gfx, intel-xe
  Cc: dri-devel, jani.nikula, uma.shankar, ville.syrjala, suraj.kandpal

From: Vandita Kulkarni <vandita.kulkarni@intel.com>

Compute frl_mode based on the sink HDMI FRL capability and the maximum
FRL rate, and pass it through intel_hdmi_mode_clock_valid() so that
modes can be validated for FRL transmission.

Higher resolution modes like 8K@60, 4K@120 need FRL support. Platforms
before MTL do not support FRL, so allow modes requiring more than 600MHz
dotclock to be enumerated only on MTL+ where FRL is supported.

Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 1773b2096e9f..09e48314c34c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2091,6 +2091,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 	struct intel_connector *connector = to_intel_connector(_connector);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
+	bool frl_mode = hdmi->has_sink_hdmi_21 && hdmi->max_frl_rate;
 	enum drm_mode_status status = MODE_OK;
 	int bpc;
 
@@ -2100,7 +2101,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 	 * least one color depth is accepted.
 	 */
 	for (bpc = 12; bpc >= 8; bpc -= 2) {
-		int hdmi_clock = intel_hdmi_clock(clock, bpc, sink_format, false);
+		int hdmi_clock = intel_hdmi_clock(clock, bpc, sink_format, frl_mode);
 
 		if (!intel_hdmi_source_bpc_possible(display, bpc))
 			continue;
@@ -2109,7 +2110,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 						  sink_format))
 			continue;
 
-		status = hdmi_port_clock_valid(hdmi, hdmi_clock, true, has_hdmi_sink, false);
+		status = hdmi_port_clock_valid(hdmi, hdmi_clock, true, has_hdmi_sink, frl_mode);
 		if (status == MODE_OK)
 			return MODE_OK;
 	}
@@ -2195,12 +2196,10 @@ intel_hdmi_mode_valid(struct drm_connector *_connector,
 	}
 
 	/*
-	 * HDMI2.1 requires higher resolution modes like 8k60, 4K120 to be
-	 * enumerated only if FRL is supported. Current platforms do not support
-	 * FRL so prune the higher resolution modes that require doctclock more
-	 * than 600MHz.
+	 * Platforms < MTL do not support FRL so prune the higher resolution
+	 * modes that require doctclock more than 600MHz.
 	 */
-	if (clock > 600000)
+	if (!HAS_HDMI_FRL(display) && clock > 600000)
 		return MODE_CLOCK_HIGH;
 
 	if (drm_mode_is_420_only(info, mode)) {
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* ✓ i915.CI.BAT: success for Enable HDMI FRL for MTL+
  2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
                   ` (43 preceding siblings ...)
  2026-08-07  4:14 ` [PATCH 44/44] drm/i915/hdmi: Enable FRL based mode clock valid Ankit Nautiyal
@ 2026-08-07 15:32 ` Patchwork
  44 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-08-07 15:32 UTC (permalink / raw)
  To: Ankit Nautiyal; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 1004 bytes --]

== Series Details ==

Series: Enable HDMI FRL for MTL+
URL   : https://patchwork.freedesktop.org/series/171758/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_18962 -> Patchwork_171758v1
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_171758v1/index.html

Participating hosts (40 -> 36)
------------------------------

  Missing    (4): bat-dg2-13 bat-dg2-9 fi-snb-2520m bat-adls-6 


Changes
-------

  No changes found


Build changes
-------------

  * Linux: CI_DRM_18962 -> Patchwork_171758v1

  CI-20190529: 20190529
  CI_DRM_18962: 01d30c194951b8794c33f0d7f559bc4a1c9b7630 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_9043: 9043
  Patchwork_171758v1: 01d30c194951b8794c33f0d7f559bc4a1c9b7630 @ git://anongit.freedesktop.org/gfx-ci/linux

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_171758v1/index.html

[-- Attachment #2: Type: text/html, Size: 1569 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* RE: [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt
  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
  1 sibling, 0 replies; 48+ messages in thread
From: Kandpal, Suraj @ 2026-09-02  6:52 UTC (permalink / raw)
  To: Nautiyal, Ankit K, intel-gfx@lists.freedesktop.org,
	intel-xe@lists.freedesktop.org
  Cc: dri-devel@lists.freedesktop.org, jani.nikula@linux.intel.com,
	Shankar, Uma, ville.syrjala@linux.intel.com

> Subject: [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt

Nit: * FRL * VBT
> 
> From: Vandita Kulkarni <vandita.kulkarni@intel.com>
> 
> Parse the maximum FRL link rate from VBT and store it for use during FRL mode
> selection and link training.
> 

Bspec link here

> Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_bios.c     | 53 +++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_bios.h     |  1 +
>  drivers/gpu/drm/i915/display/intel_vbt_defs.h |  7 +++
>  3 files changed, 61 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_bios.c
> b/drivers/gpu/drm/i915/display/intel_bios.c
> index 97cbae2e547e..6354fa4041dc 100644
> --- a/drivers/gpu/drm/i915/display/intel_bios.c
> +++ b/drivers/gpu/drm/i915/display/intel_bios.c
> @@ -2734,6 +2734,43 @@ static bool is_port_valid(struct intel_display
> *display, enum port port)
>  	return true;
>  }
> 
> +static int _intel_bios_hdmi_max_frl_rate(const struct
> +intel_bios_encoder_data *devdata) {
> +	struct intel_display *display = devdata->display;
> +
> +	if (display->vbt.version >= 237 &&
> +	    devdata->child.hdmi_max_frl_rate_valid) {
> +		switch (devdata->child.hdmi_max_frl_rate) {
> +		default:
> +		case HDMI_MAX_FRL_RATE_PLATFORM:
> +			drm_dbg_kms(display->drm,
> +				    "HDMI limited to support only TMDS
> modes\n");
> +			return 0;
> +		case HDMI_MAX_FRL_RATE_3G:
> +			return 3000000;
> +		case HDMI_MAX_FRL_RATE_6G:
> +			return 6000000;
> +		case HDMI_MAX_FRL_RATE_8G:
> +			return 8000000;
> +		case HDMI_MAX_FRL_RATE_10G:
> +			return 10000000;
> +		case HDMI_MAX_FRL_RATE_12G:
> +			return 12000000;
> +		}
> +	}
> +
> +	/*
> +	 * When hdmi_max_frl_rate_valid is 0
> +	 * Don't consider the hdmi_max_frl_rate for
> +	 * limiting the FRL Rates on FRL-capable displays
> +	 */

This comment would make more sense on top of the switch block rather than here
You don't really check the hdmi max frl rate here


> +	if (display->vbt.version >= 237 &&
> +	    display->platform.meteorlake)
> +		return 12000000;
> +
> +	return 0;
> +}
> +
>  static void print_ddi_port(const struct intel_bios_encoder_data *devdata)  {
>  	struct intel_display *display = devdata->display; @@ -2741,6 +2778,7
> @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
>  	bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb,
> supports_tbt;
>  	int dp_boost_level, dp_max_link_rate, hdmi_boost_level,
> hdmi_level_shift, max_tmds_clock;
>  	enum port port;
> +	int hdmi_max_frl_rate;
> 
>  	port = intel_bios_encoder_port(devdata);
>  	if (port == PORT_NONE)
> @@ -2806,6 +2844,12 @@ static void print_ddi_port(const struct
> intel_bios_encoder_data *devdata)
>  			    "Port %c VBT DP max link rate: %d\n",
>  			    port_name(port), dp_max_link_rate);
> 
> +	hdmi_max_frl_rate = _intel_bios_hdmi_max_frl_rate(devdata);
> +	if (hdmi_max_frl_rate)
> +		drm_dbg_kms(display->drm,
> +			    "VBT HDMI max frl rate for port %c: %d\n",
> +			    port_name(port), hdmi_max_frl_rate);
> +
>  	/*
>  	 * FIXME need to implement support for VBT
>  	 * vswing/preemph tables should this ever trigger.
> @@ -3879,3 +3923,12 @@ void intel_bios_debugfs_register(struct
> intel_display *display)
>  	debugfs_create_file("i915_vbt", 0444, display->drm->debugfs_root,
>  			    display, &intel_bios_vbt_fops);
>  }
> +
> +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder) {
> +	struct intel_display *display = to_intel_display(encoder);
> +	const struct intel_bios_encoder_data *devdata;
> +
> +	devdata = intel_bios_encoder_data_lookup(display, encoder->port);
> +	return _intel_bios_hdmi_max_frl_rate(devdata);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_bios.h
> b/drivers/gpu/drm/i915/display/intel_bios.h
> index 75dff27b4228..53d46c9fa6e1 100644
> --- a/drivers/gpu/drm/i915/display/intel_bios.h
> +++ b/drivers/gpu/drm/i915/display/intel_bios.h
> @@ -102,6 +102,7 @@ int intel_bios_hdmi_max_tmds_clock(const struct
> intel_bios_encoder_data *devdata  void intel_bios_for_each_encoder(struct
> intel_display *display,
>  				 void (*func)(struct intel_display *display,
>  					      const struct
> intel_bios_encoder_data *devdata));
> +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder);
> 
>  void intel_bios_debugfs_register(struct intel_display *display);
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> index 0dc13d080e8a..db7484542dc0 100644
> --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> @@ -381,6 +381,13 @@ struct bdb_general_features {
>  #define HDMI_MAX_DATA_RATE_340		4			/*
> 249+ */
>  #define HDMI_MAX_DATA_RATE_300		5			/*
> 249+ */
> 
> +#define HDMI_MAX_FRL_RATE_PLATFORM	0			/* 237
> */
> +#define HDMI_MAX_FRL_RATE_3G		1			/* 237
> */
> +#define HDMI_MAX_FRL_RATE_6G		2			/* 237
> */
> +#define HDMI_MAX_FRL_RATE_8G		3			/* 237
> */
> +#define HDMI_MAX_FRL_RATE_10G		4			/* 237
> */
> +#define HDMI_MAX_FRL_RATE_12G		5			/* 237
> */
> +
>  #define LEGACY_CHILD_DEVICE_CONFIG_SIZE		33
> 
>  /* DDC Bus DDI Type 155+ */
> --
> 2.50.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt
  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
  1 sibling, 0 replies; 48+ messages in thread
From: Jani Nikula @ 2026-09-02  7:20 UTC (permalink / raw)
  To: Ankit Nautiyal, intel-gfx, intel-xe
  Cc: dri-devel, uma.shankar, ville.syrjala, suraj.kandpal

On Fri, 07 Aug 2026, Ankit Nautiyal <ankit.k.nautiyal@intel.com> wrote:
> From: Vandita Kulkarni <vandita.kulkarni@intel.com>
>
> Parse the maximum FRL link rate from VBT and store it for use
> during FRL mode selection and link training.
>
> Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_bios.c     | 53 +++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_bios.h     |  1 +
>  drivers/gpu/drm/i915/display/intel_vbt_defs.h |  7 +++
>  3 files changed, 61 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
> index 97cbae2e547e..6354fa4041dc 100644
> --- a/drivers/gpu/drm/i915/display/intel_bios.c
> +++ b/drivers/gpu/drm/i915/display/intel_bios.c
> @@ -2734,6 +2734,43 @@ static bool is_port_valid(struct intel_display *display, enum port port)
>  	return true;
>  }
>  
> +static int _intel_bios_hdmi_max_frl_rate(const struct intel_bios_encoder_data *devdata)
> +{
> +	struct intel_display *display = devdata->display;
> +
> +	if (display->vbt.version >= 237 &&
> +	    devdata->child.hdmi_max_frl_rate_valid) {
> +		switch (devdata->child.hdmi_max_frl_rate) {
> +		default:
> +		case HDMI_MAX_FRL_RATE_PLATFORM:

That's 0, and we already checked that in the if.

> +			drm_dbg_kms(display->drm,
> +				    "HDMI limited to support only TMDS modes\n");
> +			return 0;
> +		case HDMI_MAX_FRL_RATE_3G:
> +			return 3000000;
> +		case HDMI_MAX_FRL_RATE_6G:
> +			return 6000000;
> +		case HDMI_MAX_FRL_RATE_8G:
> +			return 8000000;
> +		case HDMI_MAX_FRL_RATE_10G:
> +			return 10000000;
> +		case HDMI_MAX_FRL_RATE_12G:
> +			return 12000000;
> +		}
> +	}
> +
> +	/*
> +	 * When hdmi_max_frl_rate_valid is 0
> +	 * Don't consider the hdmi_max_frl_rate for
> +	 * limiting the FRL Rates on FRL-capable displays
> +	 */
> +	if (display->vbt.version >= 237 &&
> +	    display->platform.meteorlake)
> +		return 12000000;

Both the if branches have version >= 237, so you could just have if
version < 237 at the top and return early.

And what's the point of having if
(devdata->child.hdmi_max_frl_rate_valid) and switch
(devdata->child.hdmi_max_frl_rate_valid) back to back? Just handle
everything in the switch case?

> +
> +	return 0;
> +}
> +
>  static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
>  {
>  	struct intel_display *display = devdata->display;
> @@ -2741,6 +2778,7 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
>  	bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
>  	int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
>  	enum port port;
> +	int hdmi_max_frl_rate;
>  
>  	port = intel_bios_encoder_port(devdata);
>  	if (port == PORT_NONE)
> @@ -2806,6 +2844,12 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
>  			    "Port %c VBT DP max link rate: %d\n",
>  			    port_name(port), dp_max_link_rate);
>  
> +	hdmi_max_frl_rate = _intel_bios_hdmi_max_frl_rate(devdata);
> +	if (hdmi_max_frl_rate)
> +		drm_dbg_kms(display->drm,
> +			    "VBT HDMI max frl rate for port %c: %d\n",

Please stick to the same format as the other debug messages. They'll be
easier to read in the dmesg. frl -> FRL too.

> +			    port_name(port), hdmi_max_frl_rate);
> +
>  	/*
>  	 * FIXME need to implement support for VBT
>  	 * vswing/preemph tables should this ever trigger.
> @@ -3879,3 +3923,12 @@ void intel_bios_debugfs_register(struct intel_display *display)
>  	debugfs_create_file("i915_vbt", 0444, display->drm->debugfs_root,
>  			    display, &intel_bios_vbt_fops);
>  }
> +
> +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder)
> +{
> +	struct intel_display *display = to_intel_display(encoder);
> +	const struct intel_bios_encoder_data *devdata;
> +
> +	devdata = intel_bios_encoder_data_lookup(display, encoder->port);
> +	return _intel_bios_hdmi_max_frl_rate(devdata);
> +}

I don't think we want this wrapper at all. The caller can pass
encoder->devdata.

> diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
> index 75dff27b4228..53d46c9fa6e1 100644
> --- a/drivers/gpu/drm/i915/display/intel_bios.h
> +++ b/drivers/gpu/drm/i915/display/intel_bios.h
> @@ -102,6 +102,7 @@ int intel_bios_hdmi_max_tmds_clock(const struct intel_bios_encoder_data *devdata
>  void intel_bios_for_each_encoder(struct intel_display *display,
>  				 void (*func)(struct intel_display *display,
>  					      const struct intel_bios_encoder_data *devdata));
> +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder);
>  
>  void intel_bios_debugfs_register(struct intel_display *display);
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> index 0dc13d080e8a..db7484542dc0 100644
> --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
> @@ -381,6 +381,13 @@ struct bdb_general_features {
>  #define HDMI_MAX_DATA_RATE_340		4			/* 249+ */
>  #define HDMI_MAX_DATA_RATE_300		5			/* 249+ */
>  
> +#define HDMI_MAX_FRL_RATE_PLATFORM	0			/* 237 */
> +#define HDMI_MAX_FRL_RATE_3G		1			/* 237 */
> +#define HDMI_MAX_FRL_RATE_6G		2			/* 237 */
> +#define HDMI_MAX_FRL_RATE_8G		3			/* 237 */
> +#define HDMI_MAX_FRL_RATE_10G		4			/* 237 */
> +#define HDMI_MAX_FRL_RATE_12G		5			/* 237 */
> +
>  #define LEGACY_CHILD_DEVICE_CONFIG_SIZE		33
>  
>  /* DDC Bus DDI Type 155+ */

-- 
Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2026-09-02  7:21 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 33/44] drm/i915/hdmi_frl_dfm: Add support for DFM calculation with DSC Ankit Nautiyal
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox