Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
To: intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org, jani.nikula@linux.intel.com,
	uma.shankar@intel.com, ville.syrjala@linux.intel.com,
	suraj.kandpal@intel.com
Subject: [PATCH 04/44] drm/drm_scdc_helper: Add SCDC helper funcs for FRL
Date: Fri,  7 Aug 2026 09:43:49 +0530	[thread overview]
Message-ID: <20260807041430.229038-5-ankit.k.nautiyal@intel.com> (raw)
In-Reply-To: <20260807041430.229038-1-ankit.k.nautiyal@intel.com>

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


  parent reply	other threads:[~2026-08-07  4:31 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-07  4:13 [PATCH 00/44] Enable HDMI FRL for MTL+ Ankit Nautiyal
2026-08-07  4:13 ` [PATCH 01/44] drm/i915/hdmi: Parse frl max link rate from vbt Ankit Nautiyal
2026-09-02  6:52   ` Kandpal, Suraj
2026-09-02  7:20   ` Jani Nikula
2026-08-07  4:13 ` [PATCH 02/44] drm/i915/hdmi: Add new data members for FRL configuration Ankit Nautiyal
2026-08-07  4:13 ` [PATCH 03/44] drm/i915/hdmi: Add FRL link rate cap Ankit Nautiyal
2026-08-07  4:13 ` Ankit Nautiyal [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260807041430.229038-5-ankit.k.nautiyal@intel.com \
    --to=ankit.k.nautiyal@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=suraj.kandpal@intel.com \
    --cc=uma.shankar@intel.com \
    --cc=ville.syrjala@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox