From: Kunal Joshi <kunal1.joshi@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Kunal Joshi <kunal1.joshi@intel.com>, Sowmiya S <sowmiya.s@intel.com>
Subject: [PATCH i-g-t 12/13] lib/igt_dp: add DPCD link status and channel coding checks
Date: Thu, 1 Oct 2026 13:07:02 +0530 [thread overview]
Message-ID: <20261001073703.5067-13-kunal1.joshi@intel.com> (raw)
In-Reply-To: <20261001073703.5067-1-kunal1.joshi@intel.com>
Add igt_dp_link_status_ok() for checking from the sink's DPCD that all
the lanes in use are locked and aligned. 128b/132b has no clock
recovery, and has a separate bit for training failure, so handle both
channel codings, similar to drm_dp_channel_eq_ok() and the
drm_dp_128b132b_*() helpers in the kernel.
Add igt_dp_channel_coding_ok() for checking that
MAIN_LINK_CHANNEL_CODING_SET matches the expected channel coding.
Both return 1 or 0, or a negative error code if the DPCD can't be read,
so the callers can tell a failed check from a failed read.
Assisted-by: GitHub_Copilot:claude-opus-5
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
Reviewed-by: Sowmiya S <sowmiya.s@intel.com>
---
lib/igt_dp.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/igt_dp.h | 4 ++
2 files changed, 107 insertions(+)
diff --git a/lib/igt_dp.c b/lib/igt_dp.c
index 0b1fe73de..a7d9f1e77 100644
--- a/lib/igt_dp.c
+++ b/lib/igt_dp.c
@@ -281,3 +281,106 @@ int igt_dp_dpcd_read_byte(int aux_fd, unsigned int offset, uint8_t *val)
return ret == 1 ? 0 : -EIO;
}
+
+/*
+ * DPCD registers and bits used by the sink side link checks, mirroring the
+ * kernel's include/drm/display/drm_dp.h.
+ */
+#define DPCD_MAIN_LINK_CHANNEL_CODING_SET 0x108
+#define DPCD_SET_ANSI_8B10B (1 << 0)
+#define DPCD_SET_ANSI_128B132B (1 << 1)
+
+#define DPCD_LANE0_1_STATUS 0x202
+#define DPCD_LINK_STATUS_SIZE 6
+#define DPCD_LANE_CR_DONE (1 << 0)
+#define DPCD_LANE_CHANNEL_EQ_DONE (1 << 1)
+#define DPCD_LANE_SYMBOL_LOCKED (1 << 2)
+
+/* DP_LANE_ALIGN_STATUS_UPDATED, the third byte of the status block. */
+#define DPCD_INTERLANE_ALIGN_DONE (1 << 0)
+#define DPCD_128B132B_LT_FAILED (1 << 4)
+
+static uint8_t dpcd_lane_status(const uint8_t link_status[DPCD_LINK_STATUS_SIZE],
+ int lane)
+{
+ return (link_status[lane / 2] >> (4 * (lane % 2))) & 0xf;
+}
+
+/**
+ * igt_dp_channel_coding_ok: Check the channel coding the sink was told to use
+ * @aux_fd: AUX channel device file descriptor from igt_dp_aux_open()
+ * @uhbr: Whether 128b/132b is expected
+ *
+ * Read MAIN_LINK_CHANNEL_CODING_SET and check that it selects the encoding the
+ * link rate implies. This is the only direct evidence that the coding a UHBR
+ * rate implies is the coding that reached the wire.
+ *
+ * Returns:
+ * 1 when the expected coding is selected, 0 when it is not, or a negative
+ * error code when the DPCD could not be read.
+ */
+int igt_dp_channel_coding_ok(int aux_fd, bool uhbr)
+{
+ uint8_t coding;
+ int ret;
+
+ ret = igt_dp_dpcd_read_byte(aux_fd, DPCD_MAIN_LINK_CHANNEL_CODING_SET,
+ &coding);
+ if (ret < 0)
+ return ret;
+
+ return !!(coding & (uhbr ? DPCD_SET_ANSI_128B132B : DPCD_SET_ANSI_8B10B));
+}
+
+/**
+ * igt_dp_link_status_ok: Check the sink considers the link trained
+ * @aux_fd: AUX channel device file descriptor from igt_dp_aux_open()
+ * @lane_count: Number of lanes in use
+ * @uhbr: Whether the link runs at a UHBR rate, i.e. uses 128b/132b
+ *
+ * Read the link status block at DP_LANE0_1_STATUS and check that every lane in
+ * use is locked and the lanes are aligned.
+ *
+ * 128b/132b reports this differently from 8b/10b: there is no clock recovery
+ * bit, and a training failure has its own bit in
+ * DP_LANE_ALIGN_STATUS_UPDATED. Mirrors drm_dp_channel_eq_ok() and the
+ * drm_dp_128b132b_* predicates.
+ *
+ * Returns:
+ * 1 when the sink considers the link trained, 0 when it does not, or a
+ * negative error code when the DPCD could not be read.
+ */
+int igt_dp_link_status_ok(int aux_fd, int lane_count, bool uhbr)
+{
+ uint8_t link_status[DPCD_LINK_STATUS_SIZE];
+ uint8_t lane_mask;
+ uint8_t align;
+ int ret;
+ int lane;
+
+ ret = igt_dp_dpcd_read(aux_fd, DPCD_LANE0_1_STATUS, link_status,
+ sizeof(link_status));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(link_status))
+ return -EIO;
+
+ align = link_status[2];
+
+ if (uhbr && (align & DPCD_128B132B_LT_FAILED))
+ return 0;
+
+ if (!(align & DPCD_INTERLANE_ALIGN_DONE))
+ return 0;
+
+ /* 128b/132b has no clock recovery phase, so no CR_DONE bit. */
+ lane_mask = DPCD_LANE_CHANNEL_EQ_DONE | DPCD_LANE_SYMBOL_LOCKED;
+ if (!uhbr)
+ lane_mask |= DPCD_LANE_CR_DONE;
+
+ for (lane = 0; lane < lane_count; lane++)
+ if ((dpcd_lane_status(link_status, lane) & lane_mask) != lane_mask)
+ return 0;
+
+ return 1;
+}
diff --git a/lib/igt_dp.h b/lib/igt_dp.h
index 44f3b11a1..332656aae 100644
--- a/lib/igt_dp.h
+++ b/lib/igt_dp.h
@@ -36,4 +36,8 @@ int igt_dp_dpcd_read(int aux_fd, unsigned int offset, void *buf, size_t size);
int igt_dp_dpcd_read_byte(int aux_fd, unsigned int offset, uint8_t *val);
+int igt_dp_channel_coding_ok(int aux_fd, bool uhbr);
+
+int igt_dp_link_status_ok(int aux_fd, int lane_count, bool uhbr);
+
#endif
--
2.25.1
next prev parent reply other threads:[~2026-10-01 7:23 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 7:36 [PATCH i-g-t 00/13] Expand kms_dp_link_training coverage Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 01/13] lib/i915/i915_dp: add helpers for the allowed link configs debugfs Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 02/13] tests/intel/kms_dp_link_training: use i915_dp_is_uhbr_rate() Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 03/13] tests/intel/kms_dp_link_training: extract train_link_config() Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 04/13] tests/intel/kms_dp_link_training: detect links that failed training Kunal Joshi
2026-10-01 9:05 ` S, Sowmiya
2026-10-01 7:36 ` [PATCH i-g-t 05/13] tests/intel/kms_dp_link_training: use the lowest pixel clock mode Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 06/13] tests/intel/kms_dp_link_training: train all allowed link configs Kunal Joshi
2026-10-01 9:05 ` S, Sowmiya
2026-10-01 7:36 ` [PATCH i-g-t 07/13] lib/i915/i915_dp: add i915_dp_get_tc_mode() Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 08/13] tests/intel/kms_dp_link_training: log the DP link inventory Kunal Joshi
2026-10-01 7:36 ` [PATCH i-g-t 09/13] tests/intel/kms_dp_link_training: train each MST topology only once Kunal Joshi
2026-10-01 7:37 ` [PATCH i-g-t 10/13] tests/intel/kms_dp_link_training: add tbt-alt and direct link subtests Kunal Joshi
2026-10-01 7:37 ` [PATCH i-g-t 11/13] lib/igt_dp: add DPCD read helpers Kunal Joshi
2026-10-01 7:37 ` Kunal Joshi [this message]
2026-10-01 7:37 ` [PATCH i-g-t 13/13] tests/intel/kms_dp_link_training: check the link from the sink side Kunal Joshi
2026-10-01 13:13 ` ✓ i915.CI.BAT: success for Expand kms_dp_link_training coverage (rev2) Patchwork
2026-10-01 16:42 ` ✓ Xe.CI.BAT: " Patchwork
2026-10-01 21:02 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-10-05 16:06 ` Joshi, Kunal1
2026-10-02 17:18 ` ✗ i915.CI.Full: " Patchwork
2026-10-05 16:04 ` Joshi, Kunal1
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=20261001073703.5067-13-kunal1.joshi@intel.com \
--to=kunal1.joshi@intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=sowmiya.s@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