[PATCH i-g-t v7 27/48] lib/unigraf: Allows sst/mst configuration

Louis Chauvet
2026-02-23T12:09:24Z

Unigraf devices can emulate both SST and MST display port. In order to
write tests using both, add fews helper to manipulate them.

The define TSI_DPRX_NOT_DOCUMENTED_SIDEBAND_MSG_SUPPORT is taken from the
python SDK, as it was not defined by the C sdk nor documented.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
lib/unigraf/unigraf.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/unigraf/unigraf.h | 12 ++++++
2 files changed, 123 insertions(+)

diff --git a/lib/unigraf/unigraf.c b/lib/unigraf/unigraf.c
index f148d4fc099f..56a1fbe71827 100644
--- a/lib/unigraf/unigraf.c
+++ b/lib/unigraf/unigraf.c
@@ -108,6 +108,25 @@ static void unigraf_init(void)
unigraf_assert(TSIX_TS_SetConfigItem(unigraf_device, config_id, &v, sizeof(value))); \
})

+/**
+ * unigraf_read_u32 - Read a 32-bit value from a TSI configuration item with error handling
+ * @config_id: The configuration item ID to read from
+ *
+ * This macro reads a 32-bit value from the specified TSI configuration item.
+ * It includes error handling and debug output. This is a macro to have the proper
+ * line information when using unigraf_debug.
+ *
+ * Returns: The 32-bit value read from the configuration item
+ */
+#define unigraf_read_u32(config_id) \
+ ({ \
+ uint32_t value; \
+ igt_assert(unigraf_device); \
+ unigraf_assert(TSIX_TS_GetConfigItem(unigraf_device, config_id, &value, sizeof(value))); \
+ unigraf_debug("Value read: " #config_id "=%d\n", value); \
+ value; \
+ })
+
/**
* unigraf_device_count() - Return the number of scanned devices
*
@@ -309,6 +328,8 @@ void unigraf_require_device(int drm_fd)
void unigraf_reset(void)
{
unigraf_plug();
+ unigraf_set_mst_stream_count(1);
+ unigraf_set_sst();
}

/**
@@ -371,3 +392,93 @@ void unigraf_plug(void)

unigraf_write_u32(TSI_DPRX_HPD_FORCE, d);
}
+
+/**
+ * unigraf_set_sst() - Configure the device for Single Stream Transport mode
+ *
+ * This function sets the device to operate in Single Stream Transport (SST) mode.
+ */
+void unigraf_set_sst(void)
+{
+ int link_flags = 0xFFFFFFFF;
+
+ unigraf_assert(TSIX_TS_GetConfigItem(unigraf_device, TSI_DPRX_LINK_FLAGS,
+ &link_flags, sizeof(link_flags)));
+ link_flags &= ~(TSI_DPRX_LINK_FLAGS_MST | TSI_DPRX_NOT_DOCUMENTED_SIDEBAND_MSG_SUPPORT);
+ unigraf_write_u32(TSI_DPRX_LINK_FLAGS, link_flags);
+}
+
+/**
+ * unigraf_set_mst() - Configure the device for Multi Stream Transport mode
+ *
+ * This function sets the device to operate in Multi Stream Transport (MST) mode.
+ */
+void unigraf_set_mst(void)
+{
+ int link_flags = 0xFFFFFFFF;
+
+ unigraf_assert(TSIX_TS_GetConfigItem(unigraf_device, TSI_DPRX_LINK_FLAGS,
+ &link_flags, sizeof(link_flags)));
+ link_flags |= TSI_DPRX_LINK_FLAGS_MST | TSI_DPRX_NOT_DOCUMENTED_SIDEBAND_MSG_SUPPORT;
+ unigraf_write_u32(TSI_DPRX_LINK_FLAGS, link_flags);
+}
+
+/**
+ * unigraf_get_mst_stream_max_count() - Get the maximum number of stream count accepted by the
+ * device
+ * Caution: This function can be destructive to some configuration: the only way to get the
+ * information is to try and read the new value.
+ */
+int unigraf_get_mst_stream_max_count(void)
+{
+ struct TSI_DPRX_HW_CAPS_R_s caps;
+
+ unigraf_assert(TSIX_TS_GetConfigItem(unigraf_device, TSI_DPRX_HW_CAPS_R,
+ &caps, sizeof(caps)));
+
+ return caps.mst_stream_count;
+}
+
+/**
+ * unigraf_get_mst_stream_count() - Get the current number of MST streams
+ *
+ * Returns: The current number of MST streams configured on the device.
+ */
+int unigraf_get_mst_stream_count(void)
+{
+ return unigraf_read_u32(TSI_DPRX_MST_SINK_COUNT);
+}
+
+/**
+ * unigraf_set_mst_stream_count() - Set the number of accepted stream count
+ *
+ * Returns true when the stream count was properly applied, false if the final stream count
+ * is not the one requested
+ */
+bool unigraf_set_mst_stream_count(int count)
+{
+ int new_count;
+
+ igt_assert_lte(count, unigraf_get_mst_stream_max_count());
+
+ unigraf_write_u32(TSI_DPRX_MST_SINK_COUNT, count);
+ new_count = unigraf_get_mst_stream_count();
+
+ igt_warn_on_f(count != new_count,
+ "IGT:%p: Requested MST stream count (%d) differs from what was applied by the device (%d)\n",
+ unigraf_device, count, new_count);
+
+ return count == new_count;
+}
+
+/**
+ * unigraf_select_stream() - Select the active stream for the device
+ * @stream: The stream index to select
+ *
+ * This function selects the active stream for the device. The stream index
+ * should be a valid stream number that the device supports.
+ */
+void unigraf_select_stream(int stream)
+{
+ unigraf_write_u32(TSI_DPRX_STREAM_SELECT, stream);
+}
diff --git a/lib/unigraf/unigraf.h b/lib/unigraf/unigraf.h
index ae1f0d8955ab..c2caa9c2c54c 100644
--- a/lib/unigraf/unigraf.h
+++ b/lib/unigraf/unigraf.h
@@ -52,4 +52,16 @@ void unigraf_plug(void);

void unigraf_unplug(void);

+void unigraf_set_sst(void);
+
+void unigraf_set_mst(void);
+
+int unigraf_get_mst_stream_count(void);
+
+bool unigraf_set_mst_stream_count(int count);
+
+int unigraf_get_mst_stream_max_count(void);
+
+void unigraf_select_stream(int stream);
+
#endif // UNIGRAF_H

--
2.52.0