[igt-dev] [PATCH v2] [NEW]kms_chamelium: Add new EDID stress resolution test

Mark Yacoub markyacoub at chromium.org
Tue Nov 1 14:37:43 UTC 2022


[Why]
2 things that happens concurrently that we would like to test:
1. Test multiple plug/unplug of different monitors (as in different
   EDIDs) to the DUT in a short time span.
2. Test that the different EDIDs are understood well by the DUT through
   verifying the resolution after each plug and enable output.

[How]
1. Get EDID from list of EDIDs
2. Set the EDID
3. Plug and enable display
4. Check the resolution
5. Unplug and repeat.

TODO:
1. Add more EDIDs
2. Do the same for HDMI

Test Based on: [ChromeOS AutoTest display_EdidStress](https://chromium.googlesource.com/chromiumos/third_party/autotest/+/HEAD/server/site_tests/display_EdidStress/display_EdidStress.py)

Tested on: TGL with Cv3

Signed-off-by: Mark Yacoub <markyacoub at chromium.org>
---
 lib/igt_chamelium.c                      | 10 +--
 lib/igt_chamelium.h                      | 23 +++++-
 lib/meson.build                          |  4 +-
 lib/monitor_edids/dp_edids.h             | 56 +++++++++++++++
 lib/monitor_edids/monitor_edids_helper.c | 92 ++++++++++++++++++++++++
 lib/monitor_edids/monitor_edids_helper.h | 33 +++++++++
 tests/chamelium/kms_chamelium.c          | 75 +++++++++++++++++++
 7 files changed, 279 insertions(+), 14 deletions(-)
 create mode 100644 lib/monitor_edids/dp_edids.h
 create mode 100644 lib/monitor_edids/monitor_edids_helper.c
 create mode 100644 lib/monitor_edids/monitor_edids_helper.h

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index d998a1f1..db3ca0d7 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -91,14 +91,6 @@
  */
 #define CHAMELIUM_HOTPLUG_DETECTION_DELAY 10
 
-struct chamelium_edid {
-	struct chamelium *chamelium;
-	struct edid *base;
-	struct edid *raw[CHAMELIUM_MAX_PORTS];
-	int ids[CHAMELIUM_MAX_PORTS];
-	struct igt_list_head link;
-};
-
 struct chamelium_port {
 	unsigned int type;
 	int id;
@@ -688,7 +680,7 @@ static xmlrpc_value *chamelium_rpc(struct chamelium *chamelium,
 		va_end(va_args);
 	}
 	igt_assert_f(!chamelium->env.fault_occurred,
-		     "Chamelium RPC call failed: %s\n",
+		     "Chamelium RPC call[%s] failed: %s\n", method_name,
 		     chamelium->env.fault_string);
 
 	return res;
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index e1ee2b59..51e27988 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -29,10 +29,12 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stddef.h>
 #include <xf86drmMode.h>
 
 #include "igt_debugfs.h"
 #include "igt_kms.h"
+#include "igt_list.h"
 
 struct igt_fb;
 struct edid;
@@ -80,12 +82,11 @@ struct chamelium_infoframe {
 	uint8_t *payload;
 };
 
-struct chamelium_edid;
-
 /**
  * CHAMELIUM_MAX_PORTS: the maximum number of ports supported by igt_chamelium.
  *
- * For now, we have 1 VGA, 1 HDMI and 2 DisplayPort ports.
+ * On V2: 1 VGA, 1 HDMI and 2 DisplayPort ports.
+ * On V3: 2 HDMI and 2 DisplayPort ports.
  */
 #define CHAMELIUM_MAX_PORTS 4
 
@@ -105,6 +106,22 @@ extern bool igt_chamelium_allow_fsm_handling;
 
 #define CHAMELIUM_HOTPLUG_TIMEOUT 20 /* seconds */
 
+/**
+ * chamelium_edid:
+ * @chamelium: instance of the chamelium where the EDID will be applied
+ * @base: Unaltered EDID that would be used for all ports. Matches what you
+ * would get from a real monitor.
+ * @raw: EDID to be applied for each port.
+ * @ids: The ID received from Chamelium after it's created for specific ports.
+ */
+struct chamelium_edid {
+	struct chamelium *chamelium;
+	struct edid *base;
+	struct edid *raw[CHAMELIUM_MAX_PORTS];
+	int ids[CHAMELIUM_MAX_PORTS];
+	struct igt_list_head link;
+};
+
 void chamelium_deinit_rpc_only(struct chamelium *chamelium);
 struct chamelium *chamelium_init_rpc_only(void);
 struct chamelium *chamelium_init(int drm_fd, igt_display_t *display);
diff --git a/lib/meson.build b/lib/meson.build
index 1fa6d6ee..0e0fc8a1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -164,8 +164,8 @@ endif
 
 if chamelium.found()
 	lib_deps += chamelium
-	lib_sources += 'igt_chamelium.c'
-	lib_sources += 'igt_chamelium_stream.c'
+	lib_sources += [ 'igt_chamelium.c', 'igt_chamelium_stream.c' ]
+	lib_sources += 'monitor_edids/monitor_edids_helper.c'
 endif
 
 if get_option('srcdir') != ''
diff --git a/lib/monitor_edids/dp_edids.h b/lib/monitor_edids/dp_edids.h
new file mode 100644
index 00000000..1217fedc
--- /dev/null
+++ b/lib/monitor_edids/dp_edids.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * List of real DP EDIDs from popular monitors.
+ * The current list (at the time of writing this comment) is based on the top
+ * monitors used on ChromeOS.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub at chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_MONITOR_EDIDS_DP_EDIDS_H_
+#define TESTS_CHAMELIUM_MONITOR_EDIDS_DP_EDIDS_H_
+
+#include "monitor_edids_helper.h"
+
+// TODO: Add more EDIDs.
+struct monitor_edid DP_EDIDS[] = {
+	{ .name = "4K_DELL_UP3216Q_DP",
+	  .edid = "00ffffffffffff0010acf84050383230"
+		  "051a0104a5431c783aca95a6554ea126"
+		  "0f5054a54b808100b300714f8180d1c0"
+		  "0101010101017e4800e0a0381f404040"
+		  "3a00a11c2100001a000000ff00393143"
+		  "5937333538303238500a000000fc0044"
+		  "454c4c205532393137570a20000000fd"
+		  "00314c1d5e13010a2020202020200117"
+		  "02031df1501005040302071601061112"
+		  "1513141f2023091f0783010000023a80"
+		  "1871382d40582c2500a11c2100001e01"
+		  "1d8018711c1620582c2500a11c210000"
+		  "9e011d007251d01e206e285500a11c21"
+		  "00001e8c0ad08a20e02d10103e9600a1"
+		  "1c210000180000000000000000000000"
+		  "000000000000000000000000000000dd" },
+
+	{ .name = "DEL_16543_DELL_P2314T_DP",
+	  .edid = "00ffffffffffff0010ac9f404c4c3645"
+		  "10180104a5331d783ae595a656529d27"
+		  "105054a54b00714f8180a9c0d1c00101"
+		  "010101010101023a801871382d40582c"
+		  "4500fd1e1100001e000000ff00445746"
+		  "325834344645364c4c0a000000fc0044"
+		  "454c4c205032333134540a20000000fd"
+		  "00384c1e5311010a20202020202001bb"
+		  "02031cf14f9005040302071601061112"
+		  "1513141f2309070783010000023a8018"
+		  "71382d40582c4500fd1e1100001e011d"
+		  "8018711c1620582c2500fd1e1100009e"
+		  "011d007251d01e206e285500fd1e1100"
+		  "001e8c0ad08a20e02d10103e9600fd1e"
+		  "11000018000000000000000000000000"
+		  "0000000000000000000000000000003f" }
+};
+
+#endif /* TESTS_CHAMELIUM_MONITOR_EDIDS_DP_EDIDS_H_ */
\ No newline at end of file
diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
new file mode 100644
index 00000000..6f23a9e6
--- /dev/null
+++ b/lib/monitor_edids/monitor_edids_helper.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A helper library for parsing and making use of real EDID data from monitors
+ * and make them compatible with IGT and Chamelium.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub at chromium.org>
+ */
+
+#include "monitor_edids_helper.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "igt_core.h"
+
+static uint8_t convert_hex_char_to_byte(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+
+	assert(0);
+	return 0;
+}
+
+static uint8_t *get_edid_bytes_from_hex_str(const char *edid_str)
+{
+	int i;
+
+	int edid_size = strlen(edid_str) / 2; /* each asci is a nibble. */
+	uint8_t *edid = (uint8_t *)malloc(edid_size);
+
+	for (i = 0; i < edid_size; i++) {
+		edid[i] = convert_hex_char_to_byte(edid_str[i * 2]) << 4 |
+			  convert_hex_char_to_byte(edid_str[i * 2 + 1]);
+	}
+
+	return edid;
+}
+
+const char *monitor_edid_get_name(const struct monitor_edid *edid)
+{
+	return edid->name;
+}
+
+struct chamelium_edid *
+get_chameleon_edid_from_monitor_edid(struct chamelium *chamelium,
+				     const struct monitor_edid *edid)
+{
+	int i;
+	struct chamelium_edid *chamelium_edid;
+
+	uint8_t *base_edid = get_edid_bytes_from_hex_str(edid->edid);
+	assert(base_edid);
+
+	/*Print the full formatted EDID on debug. */
+	for (i = 0; i < strlen(edid->edid) / 2; i++) {
+		igt_debug("%02x ", base_edid[i]);
+		if (i % 16 == 15)
+			igt_debug("\n");
+	}
+
+	chamelium_edid = malloc(sizeof(struct chamelium_edid));
+	assert(chamelium_edid);
+
+	chamelium_edid->base = (struct edid *)base_edid;
+	chamelium_edid->chamelium = chamelium;
+	for (i = 0; i < CHAMELIUM_MAX_PORTS; i++) {
+		chamelium_edid->raw[i] = NULL;
+		chamelium_edid->ids[i] = 0;
+	}
+
+	return chamelium_edid;
+}
+
+void free_chamelium_edid_from_monitor_edid(struct chamelium_edid *edid)
+{
+	int i;
+
+	free(edid->base);
+	for (i = 0; i < CHAMELIUM_MAX_PORTS; i++)
+		free(edid->raw[i]);
+
+	free(edid);
+	edid = NULL;
+}
diff --git a/lib/monitor_edids/monitor_edids_helper.h b/lib/monitor_edids/monitor_edids_helper.h
new file mode 100644
index 00000000..46f85629
--- /dev/null
+++ b/lib/monitor_edids/monitor_edids_helper.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * A helper library for parsing and making use of real EDID data from monitors
+ * and make them compatible with IGT and Chamelium.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub at chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_MONITOR_EDIDS_MONITOR_EDIDS_HELPER_H_
+#define TESTS_CHAMELIUM_MONITOR_EDIDS_MONITOR_EDIDS_HELPER_H_
+
+#include <stdint.h>
+
+#include "igt_chamelium.h"
+
+/* Max Length can be increased as needed, when new EDIDs are added. */
+#define EDID_NAME_MAX_LEN 25
+#define EDID_HEX_STR_MAX_LEN 512
+
+struct monitor_edid {
+	char name[EDID_NAME_MAX_LEN];
+	char edid[EDID_HEX_STR_MAX_LEN + 1];
+};
+
+const char *monitor_edid_get_name(const struct monitor_edid *edid);
+struct chamelium_edid *
+get_chameleon_edid_from_monitor_edid(struct chamelium *chamelium,
+				     const struct monitor_edid *edid);
+void free_chamelium_edid_from_monitor_edid(struct chamelium_edid *edid);
+
+#endif /* TESTS_CHAMELIUM_MONITOR_EDIDS_MONITOR_EDIDS_HELPER_H_ */
\ No newline at end of file
diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
index 99cc23a1..6e77ba3c 100644
--- a/tests/chamelium/kms_chamelium.c
+++ b/tests/chamelium/kms_chamelium.c
@@ -30,11 +30,16 @@
 #include "igt_edid.h"
 #include "igt_eld.h"
 #include "igt_infoframe.h"
+#include "monitor_edids/dp_edids.h"
+#include "monitor_edids/monitor_edids_helper.h"
 
 #include <fcntl.h>
 #include <pthread.h>
 #include <string.h>
 #include <stdatomic.h>
+// #include <stdio.h>
+
+// struct chamelium_edid;
 
 enum test_modeset_mode {
 	TEST_MODESET_ON,
@@ -2541,6 +2546,71 @@ test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
 	igt_hpd_storm_reset(data->drm_fd);
 }
 
+static const char igt_edid_stress_resolution_desc[] =
+	"Stress test the DUT by testing multiple EDIDs, one right after the other,"
+	"and ensure their validity by check the real screen resolution vs the"
+	"advertised mode resultion.";
+static void edid_stress_resolution(data_t *data, struct chamelium_port *port,
+				   struct monitor_edid edids_list[],
+				   size_t edids_list_len)
+{
+	int i;
+	struct chamelium *chamelium = data->chamelium;
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	for (i = 0; i < edids_list_len; ++i) {
+		struct chamelium_edid *chamelium_edid;
+		drmModeModeInfo mode;
+		struct igt_fb fb = { 0 };
+		igt_output_t *output;
+		enum pipe pipe;
+		bool is_video_stable;
+		int screen_res_w, screen_res_h;
+
+		struct monitor_edid *monitor_edid = &edids_list[i];
+		igt_info("Testing out the EDID for %s\n",
+			 monitor_edid_get_name(monitor_edid));
+
+		/* Getting and Setting the EDID on Chamelium. */
+		chamelium_edid = get_chameleon_edid_from_monitor_edid(
+			chamelium, monitor_edid);
+		chamelium_port_set_edid(data->chamelium, port, chamelium_edid);
+		free_chamelium_edid_from_monitor_edid(chamelium_edid);
+
+		igt_flush_uevents(mon);
+		chamelium_plug(chamelium, port);
+		wait_for_connector_after_hotplug(data, mon, port,
+						 DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+
+		/* Setting an output on the screen to turn it on. */
+		mode = get_mode_for_port(chamelium, port);
+		create_fb_for_mode(data, &fb, &mode);
+		output = get_output_for_port(data, port);
+		pipe = get_pipe_for_output(&data->display, output);
+		igt_output_set_pipe(output, pipe);
+		enable_output(data, port, output, &mode, &fb);
+
+		/* Capture the screen resolution and verify. */
+		is_video_stable = chamelium_port_wait_video_input_stable(
+			chamelium, port, 5);
+		igt_assert(is_video_stable);
+
+		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
+					      &screen_res_h);
+		igt_assert(screen_res_w == fb.width);
+		igt_assert(screen_res_h == fb.height);
+
+		// Clean up
+		igt_remove_fb(data->drm_fd, &fb);
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_unplug(chamelium, port);
+	}
+
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+}
+
 #define for_each_port(p, port)            \
 	for (p = 0, port = data.ports[p]; \
 	     p < data.port_count;         \
@@ -2632,6 +2702,11 @@ igt_main
 			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
 		}
 
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution", DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS,
+					       ARRAY_SIZE(DP_EDIDS));
+
 		igt_describe(test_suspend_resume_hpd_desc);
 		connector_subtest("dp-hpd-after-suspend", DisplayPort)
 			test_suspend_resume_hpd(&data, port,
-- 
2.38.1.273.g43a17bfeac-goog



More information about the igt-dev mailing list