[PATCH i-g-t v7 28/48] lib/unigraf: Add helpers to read and write edid

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

Read and writing EDID on unigraf can be useful to emulate different
screens, add helpers to read and write them.

There is a limitation on the libTSI.so, it is only possible to read EDID
using buffers of size multiple of 128 bytes, and there is no way to query
the actual EDID size. The current implementation can only read EDID up to
2048 bytes.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
lib/unigraf/unigraf.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/unigraf/unigraf.h | 4 ++++
2 files changed, 59 insertions(+)

diff --git a/lib/unigraf/unigraf.c b/lib/unigraf/unigraf.c
index 56a1fbe71827..796848dd8fc7 100644
--- a/lib/unigraf/unigraf.c
+++ b/lib/unigraf/unigraf.c
@@ -127,6 +127,20 @@ static void unigraf_init(void)
value; \
})

+/**
+ * unigraf_write() - Helper to write a value to unigraf
+ * @config: config id to write
+ * @data: data to write
+ * @data_len: length of the data
+ * Returns
+ */
+static void unigraf_write(TSI_CONFIG_ID config, const void *data, size_t data_len)
+{
+ unigraf_debug("Writing %zu bytes to 0x%x\n", data_len, config);
+
+ unigraf_assert(TSIX_TS_SetConfigItem(unigraf_device, config, data, data_len));
+}
+
/**
* unigraf_device_count() - Return the number of scanned devices
*
@@ -332,6 +346,47 @@ void unigraf_reset(void)
unigraf_set_sst();
}

+/**
+ * unigraf_read_edid() - Read the EDID from the specified stream
+ * @stream: The stream ID to read the EDID from
+ * @edid_size: Pointer to an integer where the size of the EDID will be stored
+ *
+ * Returns: A pointer to the EDID structure, or NULL if the operation failed. The caller
+ * is responsible to free this pointer.
+ */
+struct edid *unigraf_read_edid(uint32_t stream, uint32_t *edid_size)
+{
+ void *edid;
+
+ unigraf_debug("Read EDID for stream %d...\n", stream);
+
+ edid = malloc(2048);
+ memset(edid, 0, 2048);
+
+ unigraf_write_u32(TSI_EDID_SELECT_STREAM, stream);
+ *edid_size = unigraf_assert(TSIX_TS_GetConfigItem(unigraf_device,
+ TSI_EDID_TE_INPUT,
+ edid, 2048));
+
+ return edid;
+}
+
+/**
+ * unigraf_write_edid() - Write EDID data to the specified stream
+ * @stream: The stream ID to write the EDID to
+ * @edid: Pointer to the EDID structure to write
+ * @edid_size: Size of the EDID data in bytes
+ *
+ * This function writes the provided EDID data to the specified stream.
+ */
+void unigraf_write_edid(uint32_t stream, const struct edid *edid, uint32_t edid_size)
+{
+ unigraf_debug("Write EDID for stream %d...\n", stream);
+
+ unigraf_write_u32(TSI_EDID_SELECT_STREAM, stream);
+ unigraf_write(TSI_EDID_TE_INPUT, edid, 2048);
+}
+
/**
* unigraf_hpd_assert() - Assert Hot Plug Detect signal
*
diff --git a/lib/unigraf/unigraf.h b/lib/unigraf/unigraf.h
index c2caa9c2c54c..40f706ebd483 100644
--- a/lib/unigraf/unigraf.h
+++ b/lib/unigraf/unigraf.h
@@ -42,6 +42,10 @@ void unigraf_require_device(int drm_fd);

void unigraf_reset(void);

+struct edid *unigraf_read_edid(uint32_t stream, uint32_t *edid_size);
+
+void unigraf_write_edid(uint32_t stream, const struct edid *edid, uint32_t edid_size);
+
void unigraf_hpd_deassert(void);

void unigraf_hpd_pulse(int duration);

--
2.52.0