All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
@ 2022-11-30 20:45 Mark Yacoub
  2022-11-30 21:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for " Patchwork
                   ` (13 more replies)
  0 siblings, 14 replies; 25+ messages in thread
From: Mark Yacoub @ 2022-11-30 20:45 UTC (permalink / raw)
  To: igt-dev
  Cc: robdclark, vsuley, petri.latvala, ihf, amstan, kalin, seanpaul,
	matthewtlam, markyacoub, khaled.almahallawy

[Why]
kms_chamelium tests file has grown so much and became a bit big to
manage.
Splitting specific tests like we do for kms_ tests into separate files
puts logically related functionalities into the same place so tests are
more clear.

[How]
Split kms_chamelium into 4 different tests, each testing something
specific. The tests are:
1. kms_chamelium_audio
2. kms_chamelium_edid
3. kms_chamelium_frames
4. kms_chamelium_hpd
5. kms_chamelium_color which used to be kms_color_chamelium but renamed
   for consistency.

All common code lives in kms_chamelium_helper and the function names
have a chamelium_ prefix.

Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
---
 docs/chamelium.txt                            |    2 +-
 lib/igt_edid.h                                |    1 +
 lib/igt_eld.h                                 |    1 +
 lib/monitor_edids/monitor_edids_helper.c      |    2 +-
 tests/chamelium/kms_chamelium.c               | 3132 -----------------
 tests/chamelium/kms_chamelium_audio.c         |  858 +++++
 ...olor_chamelium.c => kms_chamelium_color.c} |    0
 tests/chamelium/kms_chamelium_edid.c          |  532 +++
 tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
 tests/chamelium/kms_chamelium_helper.c        |  330 ++
 tests/chamelium/kms_chamelium_helper.h        |   74 +
 tests/chamelium/kms_chamelium_hpd.c           |  512 +++
 tests/intel-ci/blacklist.txt                  |    2 +-
 tests/intel-ci/fast-feedback.testlist         |   18 +-
 tests/kms_color_helper.h                      |    2 +-
 tests/meson.build                             |   14 +-
 tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
 17 files changed, 3429 insertions(+), 3164 deletions(-)
 delete mode 100644 tests/chamelium/kms_chamelium.c
 create mode 100644 tests/chamelium/kms_chamelium_audio.c
 rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
 create mode 100644 tests/chamelium/kms_chamelium_edid.c
 create mode 100644 tests/chamelium/kms_chamelium_frames.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.h
 create mode 100644 tests/chamelium/kms_chamelium_hpd.c

diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index c4c22468..f82c8b0c 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -241,7 +241,7 @@ Current Support in IGT
 
 Support for the Chamelium platform in IGT is found in the following places:
 * lib/igt_chamelium.c: library with Chamelium-related helpers
-* tests/kms_chamelium.c: sub-tests using the Chamelium
+* tests/kms_chamelium_*.c: sub-tests using the Chamelium
 
 As of early April 2019, the following features are tested by IGT:
 * Pixel-by-pixel frame integrity tests for DP and HDMI
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 477f16c2..85a9ef5e 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdint.h>
+#include <stddef.h>
 
 #include <xf86drmMode.h>
 
diff --git a/lib/igt_eld.h b/lib/igt_eld.h
index 30d7012d..1a46b6d2 100644
--- a/lib/igt_eld.h
+++ b/lib/igt_eld.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stddef.h>
 
 #include "igt_edid.h"
 
diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
index 41f199bd..1cbf1c22 100644
--- a/lib/monitor_edids/monitor_edids_helper.c
+++ b/lib/monitor_edids/monitor_edids_helper.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 /*
  * A helper library for parsing and making use of real EDID data from monitors
  * and make them compatible with IGT and Chamelium.
diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
deleted file mode 100644
index 3c4b4d75..00000000
--- a/tests/chamelium/kms_chamelium.c
+++ /dev/null
@@ -1,3132 +0,0 @@
-/*
- * Copyright © 2016 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Lyude Paul <lyude@redhat.com>
- */
-
-#include "config.h"
-#include "igt.h"
-#include "igt_vc4.h"
-#include "igt_edid.h"
-#include "igt_eld.h"
-#include "igt_infoframe.h"
-#include "monitor_edids/dp_edids.h"
-#include "monitor_edids/hdmi_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,
-	TEST_MODESET_ON_OFF,
-	TEST_MODESET_OFF,
-};
-
-typedef struct {
-	struct chamelium *chamelium;
-	struct chamelium_port **ports;
-	igt_display_t display;
-	int port_count;
-
-	int drm_fd;
-
-	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
-} data_t;
-
-#define ONLINE_TIMEOUT 20 /* seconds */
-
-#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
-#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
-
-#define HPD_TOGGLE_COUNT_VGA 5
-#define HPD_TOGGLE_COUNT_DP_HDMI 15
-#define HPD_TOGGLE_COUNT_FAST 3
-
-static void
-get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
-{
-	drmModeConnector *connector;
-	uint64_t link_status;
-	drmModePropertyPtr prop;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		connector = chamelium_port_get_connector(data->chamelium,
-							 data->ports[p], false);
-
-		igt_assert(kmstest_get_property(data->drm_fd,
-						connector->connector_id,
-						DRM_MODE_OBJECT_CONNECTOR,
-						"link-status", NULL,
-						&link_status, &prop));
-
-		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
-
-		drmModeFreeProperty(prop);
-		drmModeFreeConnector(connector);
-	}
-}
-
-/* Wait for hotplug and return the remaining time left from timeout */
-static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
-{
-	struct timespec start, end;
-	int elapsed;
-	bool detected;
-
-	igt_assert_eq(igt_gettime(&start), 0);
-	detected = igt_hotplug_detected(mon, *timeout);
-	igt_assert_eq(igt_gettime(&end), 0);
-
-	elapsed = igt_time_elapsed(&start, &end);
-	igt_assert_lte(0, elapsed);
-	*timeout = max(0, *timeout - elapsed);
-
-	return detected;
-}
-
-static void
-wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
-				 struct chamelium_port *port,
-				 drmModeConnection status)
-{
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int hotplug_count = 0;
-
-	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
-			  chamelium_port_get_name(port),
-			  kmstest_connector_status_str(status));
-
-	while (timeout > 0) {
-		if (!wait_for_hotplug(mon, &timeout))
-			break;
-
-		hotplug_count++;
-
-		if (chamelium_reprobe_connector(&data->display, data->chamelium,
-						port) == status)
-			return;
-	}
-
-	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
-			    chamelium_port_get_name(port),
-			    kmstest_connector_status_str(status),
-			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
-}
-
-
-static int chamelium_vga_modes[][2] = {
-	{ 1600, 1200 },
-	{ 1920, 1200 },
-	{ 1920, 1080 },
-	{ 1680, 1050 },
-	{ 1280, 1024 },
-	{ 1280, 960 },
-	{ 1440, 900 },
-	{ 1280, 800 },
-	{ 1024, 768 },
-	{ 1360, 768 },
-	{ 1280, 720 },
-	{ 800, 600 },
-	{ 640, 480 },
-	{ -1, -1 },
-};
-
-static bool
-prune_vga_mode(data_t *data, drmModeModeInfo *mode)
-{
-	int i = 0;
-
-	while (chamelium_vga_modes[i][0] != -1) {
-		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
-		    mode->vdisplay == chamelium_vga_modes[i][1])
-			return false;
-
-		i++;
-	}
-
-	return true;
-}
-
-static bool
-check_analog_bridge(data_t *data, struct chamelium_port *port)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-	uint64_t edid_blob_id;
-	const struct edid *edid;
-	char edid_vendor[3];
-
-	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
-		drmModeFreeConnector(connector);
-		return false;
-	}
-
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	edid = (const struct edid *) edid_blob->data;
-	edid_get_mfg(edid, edid_vendor);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-
-	/* Analog bridges provide their own EDID */
-	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
-	    edid_vendor[2] != 'T')
-		return true;
-
-	return false;
-}
-
-static void chamelium_paint_xr24_pattern(uint32_t *data,
-					 size_t width, size_t height,
-					 size_t stride, size_t block_size)
-{
-	uint32_t colors[] = { 0xff000000,
-			      0xffff0000,
-			      0xff00ff00,
-			      0xff0000ff,
-			      0xffffffff };
-	unsigned i, j;
-
-	for (i = 0; i < height; i++)
-		for (j = 0; j < width; j++)
-			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
-}
-
-static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
-				    uint32_t fourcc, size_t block_size,
-				    struct igt_fb *fb)
-{
-	int fb_id;
-	void *ptr;
-
-	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
-
-	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
-			      DRM_FORMAT_MOD_LINEAR, fb);
-	igt_assert(fb_id > 0);
-
-	ptr = igt_fb_map_buffer(fb->fd, fb);
-	igt_assert(ptr);
-
-	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
-				     block_size);
-	igt_fb_unmap_buffer(fb, ptr);
-
-	return fb_id;
-}
-
-static void
-enable_output(data_t *data,
-	      struct chamelium_port *port,
-	      igt_output_t *output,
-	      drmModeModeInfo *mode,
-	      struct igt_fb *fb)
-{
-	igt_display_t *display = output->display;
-	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-
-	igt_assert(primary);
-
-	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
-	igt_plane_set_fb(primary, fb);
-	igt_output_override_mode(output, mode);
-
-	/* Clear any color correction values that might be enabled */
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
-
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
-		usleep(250000);
-
-	drmModeFreeConnector(connector);
-}
-
-static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
-{
-	enum pipe pipe;
-
-	for_each_pipe(display, pipe) {
-		if (igt_pipe_connector_valid(pipe, output)) {
-			return pipe;
-		}
-	}
-
-	igt_assert_f(false, "No pipe found for output %s\n",
-		     igt_output_name(output));
-}
-
-static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
-{
-	int fb_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, fb);
-
-	igt_assert(fb_id > 0);
-}
-
-static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
-								   port, false);
-	drmModeModeInfo mode;
-	igt_assert(&connector->modes[0] != NULL);
-	memcpy(&mode, &connector->modes[0], sizeof(mode));
-	drmModeFreeConnector(connector);
-	return mode;
-}
-
-static igt_output_t *get_output_for_port(data_t *data,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector =
-		chamelium_port_get_connector(data->chamelium, port, true);
-	igt_output_t *output = igt_output_from_connector(&data->display,
-							 connector);
-	drmModeFreeConnector(connector);
-	igt_assert(output != NULL);
-	return output;
-}
-
-static const char test_hotplug_for_each_pipe_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug for each pipe with valid output";
-static void
-test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	enum pipe pipe;
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	chamelium_reset_state(&data->display,
-			      data->chamelium,
-			      port,
-			      data->ports,
-			      data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	/* Disconnect if any port got connected */
-	chamelium_unplug(data->chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port,
-			DRM_MODE_DISCONNECTED);
-
-	for_each_pipe(&data->display, pipe) {
-		igt_flush_uevents(mon);
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-		output = get_output_for_port(data, port);
-
-		/* If pipe is valid for output then set it */
-		if (igt_pipe_connector_valid(pipe, output)) {
-			igt_output_set_pipe(output, pipe);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-
-		chamelium_unplug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_DISCONNECTED);
-		igt_flush_uevents(mon);
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_basic_hotplug_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug";
-static void
-test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
-	     enum test_modeset_mode modeset_mode)
-{
-	int i;
-	enum pipe pipe;
-	struct igt_fb fb = {0};
-	drmModeModeInfo mode;
-	struct udev_monitor *mon = igt_watch_uevents();
-	igt_output_t *output = get_output_for_port(data, port);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-
-	for (i = 0; i < toggle_count; i++) {
-		igt_flush_uevents(mon);
-
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF ||
-		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
-			if (i == 0) {
-				/* We can only get mode and pipe once we are connected */
-				output = get_output_for_port(data, port);
-				pipe = get_pipe_for_output(&data->display, output);
-				mode = get_mode_for_port(data->chamelium, port);
-				create_fb_for_mode(data, &fb, &mode);
-			}
-
-			igt_output_set_pipe(output, pipe);
-			enable_output(data, port, output, &mode, &fb);
-		}
-
-		/* Now check if we get a hotplug from disconnection */
-		chamelium_unplug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_DISCONNECTED);
-
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF) {
-			igt_output_set_pipe(output, PIPE_NONE);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static void set_edid(data_t *data, struct chamelium_port *port,
-		     enum igt_custom_edid_type edid)
-{
-	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
-}
-
-static const char igt_custom_edid_type_read_desc[] =
-	"Make sure the EDID exposed by KMS is the same as the screen's";
-static void
-igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector;
-	size_t raw_edid_size;
-	const struct edid *raw_edid;
-	uint64_t edid_blob_id;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_skip_on(check_analog_bridge(data, port));
-
-	connector = chamelium_port_get_connector(data->chamelium, port, true);
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob_id != 0);
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
-	raw_edid_size = edid_get_size(raw_edid);
-	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-}
-
-static void
-try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-		       enum igt_suspend_state state, enum igt_suspend_test test,
-		       struct udev_monitor *mon, bool connected)
-{
-	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
-						     DRM_MODE_CONNECTED;
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int delay;
-	int p;
-
-	igt_flush_uevents(mon);
-
-	delay = igt_get_autoresume_delay(state) * 1000 / 2;
-
-	if (port) {
-		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
-					      !connected);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			port = data->ports[p];
-			chamelium_schedule_hpd_toggle(data->chamelium, port,
-						      delay, !connected);
-		}
-
-		port = NULL;
-	}
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(wait_for_hotplug(mon, &timeout));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	if (port) {
-		igt_assert_eq(chamelium_reprobe_connector(&data->display,
-							  data->chamelium,
-							  port),
-							  target_state);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			drmModeConnection current_state;
-
-			port = data->ports[p];
-			/*
-			 * There could be as many hotplug events sent by
-			 * driver as connectors we scheduled an HPD toggle on
-			 * above, depending on timing. So if we're not seeing
-			 * the expected connector state try to wait for an HPD
-			 * event for each connector/port.
-			 */
-			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			if (p > 0 && current_state != target_state) {
-				igt_assert(wait_for_hotplug(mon, &timeout));
-				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			}
-
-			igt_assert_eq(current_state, target_state);
-		}
-
-		port = NULL;
-	}
-}
-
-static const char test_suspend_resume_hpd_desc[] =
-	"Toggle HPD during suspend, check that uevents are sent and connector "
-	"status is updated";
-static void
-test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-			enum igt_suspend_state state,
-			enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_hpd_common_desc[] =
-	"Toggle HPD during suspend on all connectors, check that uevents are "
-	"sent and connector status is updated";
-static void
-test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
-			       enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	struct chamelium_port *port;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		port = data->ports[p];
-		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_edid_change_desc[] =
-	"Simulate a screen being unplugged and another screen being plugged "
-	"during suspend, check that a uevent is sent and connector status is "
-	"updated";
-static void
-test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
-				enum igt_suspend_state state,
-				enum igt_suspend_test test,
-				enum igt_custom_edid_type edid,
-				enum igt_custom_edid_type alt_edid)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	bool link_status_failed[2][data->port_count];
-	int p;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Catch the event and flush all remaining ones. */
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_flush_uevents(mon);
-
-	/* First plug in the port */
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	/*
-	 * Change the edid before we suspend. On resume, the machine should
-	 * notice the EDID change and fire a hotplug event.
-	 */
-	set_edid(data, port, alt_edid);
-
-	get_connectors_link_status_failed(data, link_status_failed[0]);
-
-	igt_flush_uevents(mon);
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	get_connectors_link_status_failed(data, link_status_failed[1]);
-
-	for (p = 0; p < data->port_count; p++)
-		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
-}
-
-static igt_output_t *
-prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	/* The chamelium's default EDID has a lot of resolutions, way more then
-	 * we need to test. Additionally the default EDID doesn't support HDMI
-	 * audio.
-	 */
-	set_edid(data, port, edid);
-
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_display_reset(display);
-
-	output = get_output_for_port(data, port);
-
-	/* Refresh pipe to update connected status */
-	igt_output_set_pipe(output, PIPE_NONE);
-
-	pipe = get_pipe_for_output(display, output);
-	igt_output_set_pipe(output, pipe);
-
-	return output;
-}
-
-static void do_test_display(data_t *data, struct chamelium_port *port,
-			    igt_output_t *output, drmModeModeInfo *mode,
-			    uint32_t fourcc, enum chamelium_check check,
-			    int count)
-{
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb frame_fb, fb;
-	int i, fb_id, captured_frame_count;
-	int frame_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &fb);
-	igt_assert(fb_id > 0);
-
-	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
-				  DRM_FORMAT_MOD_LINEAR);
-	igt_assert(frame_id > 0);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-
-	enable_output(data, port, output, mode, &frame_fb);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		igt_crc_t *expected_crc;
-		igt_crc_t *crc;
-
-		/* We want to keep the display running for a little bit, since
-		 * there's always the potential the driver isn't able to keep
-		 * the display running properly for very long
-		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == count);
-
-		igt_debug("Captured %d frames\n", captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		for (i = 0; i < captured_frame_count; i++)
-			chamelium_assert_crc_eq_or_dump(data->chamelium,
-							expected_crc, &crc[i],
-							&fb, i);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_ANALOG ||
-		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		igt_assert(count == 1);
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-
-		if (check == CHAMELIUM_CHECK_ANALOG)
-			chamelium_crop_analog_frame(dump, mode->hdisplay,
-						    mode->vdisplay);
-
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	igt_remove_fb(data->drm_fd, &frame_fb);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static const char test_display_one_mode_desc[] =
-	"Pick the first mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_one_mode(data_t *data, struct chamelium_port *port,
-				  uint32_t fourcc, enum chamelium_check check,
-				  int count)
-{
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	igt_output_t *output;
-	igt_plane_t *primary;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
-
-	mode = &connector->modes[0];
-	if (check == CHAMELIUM_CHECK_ANALOG) {
-		bool bridge = check_analog_bridge(data, port);
-
-		igt_assert(!(bridge && prune_vga_mode(data, mode)));
-	}
-
-	do_test_display(data, port, output, mode, fourcc, check, count);
-
-	drmModeFreeConnector(connector);
-}
-
-static const char test_display_all_modes_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_all_modes(data_t *data, struct chamelium_port *port,
-				   uint32_t fourcc, enum chamelium_check check,
-				   int count)
-{
-	bool bridge;
-	int i, count_modes;
-
-	if (check == CHAMELIUM_CHECK_ANALOG)
-		bridge = check_analog_bridge(data, port);
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-		igt_require(igt_plane_has_format_mod(primary, fourcc,
-			    DRM_FORMAT_MOD_LINEAR));
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
-		    prune_vga_mode(data, mode))
-			continue;
-
-		do_test_display(data, port, output, mode, fourcc, check,
-				count);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-static const char test_display_frame_dump_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then download the captured frames and compare them "
-	"bit-by-bit to the sent ones";
-static void
-test_display_frame_dump(data_t *data, struct chamelium_port *port)
-{
-
-	int i, count_modes;
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		struct igt_fb fb;
-		struct chamelium_frame_dump *frame;
-		drmModeModeInfo *mode;
-		drmModeConnector *connector;
-		int fb_id, j;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Reading frame dumps from Chamelium...\n");
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
-		for (j = 0; j < 5; j++) {
-			frame = chamelium_read_captured_frame(data->chamelium,
-							      j);
-			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
-			chamelium_destroy_frame_dump(frame);
-		}
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
-
-static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
-		       drmModeModeInfo *mode)
-{
-	struct chamelium_video_params video_params = {0};
-	double mode_clock;
-	int mode_hsync_offset, mode_vsync_offset;
-	int mode_hsync_width, mode_vsync_width;
-	int mode_hsync_polarity, mode_vsync_polarity;
-
-	chamelium_port_get_video_params(chamelium, port, &video_params);
-
-	mode_clock = (double) mode->clock / 1000;
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
-		/* this is what chamelium understands as offsets for DP */
-		mode_hsync_offset = mode->htotal - mode->hsync_start;
-		mode_vsync_offset = mode->vtotal - mode->vsync_start;
-	} else {
-		/* and this is what they are for other connectors */
-		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
-		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
-	}
-
-	mode_hsync_width = mode->hsync_end - mode->hsync_start;
-	mode_vsync_width = mode->vsync_end - mode->vsync_start;
-
-	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-
-	igt_debug("Checking video mode:\n");
-	igt_debug("clock: got %f, expected %f ± %f%%\n",
-		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
-	igt_debug("hactive: got %d, expected %d\n",
-		  video_params.hactive, mode->hdisplay);
-	igt_debug("vactive: got %d, expected %d\n",
-		  video_params.vactive, mode->vdisplay);
-	igt_debug("hsync_offset: got %d, expected %d\n",
-		  video_params.hsync_offset, mode_hsync_offset);
-	igt_debug("vsync_offset: got %d, expected %d\n",
-		  video_params.vsync_offset, mode_vsync_offset);
-	igt_debug("htotal: got %d, expected %d\n",
-		  video_params.htotal, mode->htotal);
-	igt_debug("vtotal: got %d, expected %d\n",
-		  video_params.vtotal, mode->vtotal);
-	igt_debug("hsync_width: got %d, expected %d\n",
-		  video_params.hsync_width, mode_hsync_width);
-	igt_debug("vsync_width: got %d, expected %d\n",
-		  video_params.vsync_width, mode_vsync_width);
-	igt_debug("hsync_polarity: got %d, expected %d\n",
-		  video_params.hsync_polarity, mode_hsync_polarity);
-	igt_debug("vsync_polarity: got %d, expected %d\n",
-		  video_params.vsync_polarity, mode_vsync_polarity);
-
-	if (!isnan(video_params.clock)) {
-		igt_assert(video_params.clock >
-			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
-		igt_assert(video_params.clock <
-			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
-	}
-	igt_assert(video_params.hactive == mode->hdisplay);
-	igt_assert(video_params.vactive == mode->vdisplay);
-	igt_assert(video_params.hsync_offset == mode_hsync_offset);
-	igt_assert(video_params.vsync_offset == mode_vsync_offset);
-	igt_assert(video_params.htotal == mode->htotal);
-	igt_assert(video_params.vtotal == mode->vtotal);
-	igt_assert(video_params.hsync_width == mode_hsync_width);
-	igt_assert(video_params.vsync_width == mode_vsync_width);
-	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
-	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
-}
-
-static const char test_mode_timings_desc[] =
-	"For each mode of the IGT base EDID, perform a modeset and check the "
-	"mode detected by the Chamelium receiver matches the mode we set";
-static void test_mode_timings(data_t *data, struct chamelium_port *port)
-{
-	int i, count_modes;
-
-	i = 0;
-	igt_require(chamelium_supports_get_video_params(data->chamelium));
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-		int fb_id;
-		struct igt_fb fb;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port, false);
-		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		/* Trigger the FSM */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
-
-		check_mode(data->chamelium, port, mode);
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-struct vic_mode {
-	int hactive, vactive;
-	int vrefresh; /* Hz */
-	uint32_t picture_ar;
-};
-
-/* Maps Video Identification Codes to a mode */
-static const struct vic_mode vic_modes[] = {
-	[16] = {
-		.hactive = 1920,
-		.vactive = 1080,
-		.vrefresh = 60,
-		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
-	},
-};
-
-/* Maps aspect ratios to their mode flag */
-static const uint32_t mode_ar_flags[] = {
-	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
-};
-
-static enum infoframe_avi_picture_aspect_ratio
-get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
-{
-	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
-	switch (aspect_ratio) {
-	case DRM_MODE_PICTURE_ASPECT_4_3:
-		return INFOFRAME_AVI_PIC_AR_4_3;
-	case DRM_MODE_PICTURE_ASPECT_16_9:
-		return INFOFRAME_AVI_PIC_AR_16_9;
-	default:
-		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
-	}
-}
-
-static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
-				 drmModeModeInfo *drm_mode)
-{
-	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
-
-	return vic_mode->hactive == drm_mode->hdisplay &&
-	       vic_mode->vactive == drm_mode->vdisplay &&
-	       vic_mode->vrefresh == drm_mode->vrefresh &&
-	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
-}
-
-static const char test_display_aspect_ratio_desc[] =
-	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
-	"check they include the relevant fields";
-static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	int fb_id, i;
-	struct igt_fb fb;
-	bool found, ok;
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_avi infoframe_avi;
-	uint8_t vic = 16; /* TODO: test more VICs */
-	const struct vic_mode *vic_mode;
-	uint32_t aspect_ratio;
-	enum infoframe_avi_picture_aspect_ratio frame_ar;
-
-	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	vic_mode = &vic_modes[vic];
-	aspect_ratio = vic_mode->picture_ar;
-
-	found = false;
-	igt_assert(connector->count_modes > 0);
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-
-		if (vic_mode_matches_drm(vic_mode, mode)) {
-			found = true;
-			break;
-		}
-	}
-	igt_assert_f(found,
-		     "Failed to find mode with the correct aspect ratio\n");
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
-						 CHAMELIUM_INFOFRAME_AVI);
-	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
-
-	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
-				 infoframe->payload, infoframe->payload_size);
-	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
-
-	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
-
-	igt_debug("Checking AVI InfoFrame\n");
-	igt_debug("Picture aspect ratio: got %d, expected %d\n",
-		  infoframe_avi.picture_aspect_ratio, frame_ar);
-	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
-		  infoframe_avi.vic, vic);
-
-	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
-	igt_assert(infoframe_avi.vic == vic);
-
-	chamelium_infoframe_destroy(infoframe);
-	igt_remove_fb(data->drm_fd, &fb);
-	drmModeFreeConnector(connector);
-}
-
-
-/* Playback parameters control the audio signal we synthesize and send */
-#define PLAYBACK_CHANNELS 2
-#define PLAYBACK_SAMPLES 1024
-
-/* Capture paremeters control the audio signal we receive */
-#define CAPTURE_SAMPLES 2048
-
-#define AUDIO_TIMEOUT 2000 /* ms */
-/* A streak of 3 gives confidence that the signal is good. */
-#define MIN_STREAK 3
-
-#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
-#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
-#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
-
-/* TODO: enable >48KHz rates, these are not reliable */
-static int test_sampling_rates[] = {
-	32000,
-	44100,
-	48000,
-	/* 88200, */
-	/* 96000, */
-	/* 176400, */
-	/* 192000, */
-};
-
-static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
-
-/* Test frequencies (Hz): a sine signal will be generated for each.
- *
- * Depending on the sampling rate chosen, it might not be possible to properly
- * detect the generated sine (see Nyquist–Shannon sampling theorem).
- * Frequencies that can't be reliably detected will be automatically pruned in
- * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
- * tested with a 192KHz sampling rate.
- */
-static int test_frequencies[] = {
-	300,
-	600,
-	1200,
-	10000,
-	80000,
-};
-
-static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
-
-static const snd_pcm_format_t test_formats[] = {
-	SND_PCM_FORMAT_S16_LE,
-	SND_PCM_FORMAT_S24_LE,
-	SND_PCM_FORMAT_S32_LE,
-};
-
-static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
-
-struct audio_state {
-	struct alsa *alsa;
-	struct chamelium *chamelium;
-	struct chamelium_port *port;
-	struct chamelium_stream *stream;
-
-	/* The capture format is only available after capture has started. */
-	struct {
-		snd_pcm_format_t format;
-		int channels;
-		int rate;
-	} playback, capture;
-
-	char *name;
-	struct audio_signal *signal; /* for frequencies test only */
-	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	size_t recv_pages;
-	int msec;
-
-	int dump_fd;
-	char *dump_path;
-
-	pthread_t thread;
-	atomic_bool run;
-	atomic_bool positive; /* for pulse test only */
-};
-
-static void audio_state_init(struct audio_state *state, data_t *data,
-			     struct alsa *alsa, struct chamelium_port *port,
-			     snd_pcm_format_t format, int channels, int rate)
-{
-	memset(state, 0, sizeof(*state));
-	state->dump_fd = -1;
-
-	state->alsa = alsa;
-	state->chamelium = data->chamelium;
-	state->port = port;
-
-	state->playback.format = format;
-	state->playback.channels = channels;
-	state->playback.rate = rate;
-
-	alsa_configure_output(alsa, format, channels, rate);
-
-	state->stream = chamelium_stream_init();
-	igt_assert_f(state->stream,
-		     "Failed to initialize Chamelium stream client\n");
-}
-
-static void audio_state_fini(struct audio_state *state)
-{
-	chamelium_stream_deinit(state->stream);
-	free(state->name);
-}
-
-static void *run_audio_thread(void *data)
-{
-	struct alsa *alsa = data;
-
-	alsa_run(alsa, -1);
-	return NULL;
-}
-
-static void audio_state_start(struct audio_state *state, const char *name)
-{
-	int ret;
-	bool ok;
-	size_t i, j;
-	enum chamelium_stream_realtime_mode stream_mode;
-	char dump_suffix[64];
-
-	free(state->name);
-	state->name = strdup(name);
-	state->recv_pages = 0;
-	state->msec = 0;
-
-	igt_debug("Starting %s test with playback format %s, "
-		  "sampling rate %d Hz and %d channels\n",
-		  name, snd_pcm_format_name(state->playback.format),
-		  state->playback.rate, state->playback.channels);
-
-	chamelium_start_capturing_audio(state->chamelium, state->port, false);
-
-	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
-	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
-	igt_assert_f(ok, "Failed to start streaming audio capture\n");
-
-	/* Start playing audio */
-	state->run = true;
-	ret = pthread_create(&state->thread, NULL,
-			     run_audio_thread, state->alsa);
-	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
-
-	/* The Chamelium device only supports this PCM format. */
-	state->capture.format = SND_PCM_FORMAT_S32_LE;
-
-	/* Only after we've started playing audio, we can retrieve the capture
-	 * format used by the Chamelium device. */
-	chamelium_get_audio_format(state->chamelium, state->port,
-				   &state->capture.rate,
-				   &state->capture.channels);
-	if (state->capture.rate == 0) {
-		igt_debug("Audio receiver doesn't indicate the capture "
-			 "sampling rate, assuming it's %d Hz\n",
-			 state->playback.rate);
-		state->capture.rate = state->playback.rate;
-	}
-
-	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
-					    state->channel_mapping);
-	/* Make sure we can capture all channels we send. */
-	for (i = 0; i < state->playback.channels; i++) {
-		ok = false;
-		for (j = 0; j < state->capture.channels; j++) {
-			if (state->channel_mapping[j] == i) {
-				ok = true;
-				break;
-			}
-		}
-		igt_assert_f(ok, "Cannot capture all channels\n");
-	}
-
-	if (igt_frame_dump_is_enabled()) {
-		snprintf(dump_suffix, sizeof(dump_suffix),
-			 "capture-%s-%s-%dch-%dHz",
-			 name, snd_pcm_format_name(state->playback.format),
-			 state->playback.channels, state->playback.rate);
-
-		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
-							      state->capture.rate,
-							      state->capture.channels,
-							      &state->dump_path);
-		igt_assert_f(state->dump_fd >= 0,
-			     "Failed to create audio dump file\n");
-	}
-}
-
-static void audio_state_receive(struct audio_state *state,
-				int32_t **recv, size_t *recv_len)
-{
-	bool ok;
-	size_t page_count;
-	size_t recv_size;
-
-	ok = chamelium_stream_receive_realtime_audio(state->stream,
-						     &page_count,
-						     recv, recv_len);
-	igt_assert_f(ok, "Failed to receive audio from stream server\n");
-
-	state->msec = state->recv_pages * *recv_len
-		      / (double) state->capture.channels
-		      / (double) state->capture.rate * 1000;
-	state->recv_pages++;
-
-	if (state->dump_fd >= 0) {
-		recv_size = *recv_len * sizeof(int32_t);
-		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
-			     "Failed to write to audio dump file\n");
-	}
-}
-
-static void audio_state_stop(struct audio_state *state, bool success)
-{
-	bool ok;
-	int ret;
-	struct chamelium_audio_file *audio_file;
-	enum igt_log_level log_level;
-
-	igt_debug("Stopping audio playback\n");
-	state->run = false;
-	ret = pthread_join(state->thread, NULL);
-	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
-
-	ok = chamelium_stream_stop_realtime_audio(state->stream);
-	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
-
-	audio_file = chamelium_stop_capturing_audio(state->chamelium,
-						    state->port);
-	if (audio_file) {
-		igt_debug("Audio file saved on the Chamelium in %s\n",
-			  audio_file->path);
-		chamelium_destroy_audio_file(audio_file);
-	}
-
-	if (state->dump_fd >= 0) {
-		close(state->dump_fd);
-		state->dump_fd = -1;
-
-		if (success) {
-			/* Test succeeded, no need to keep the captured data */
-			unlink(state->dump_path);
-		} else
-			igt_debug("Saved captured audio data to %s\n",
-				  state->dump_path);
-		free(state->dump_path);
-		state->dump_path = NULL;
-	}
-
-	if (success)
-		log_level = IGT_LOG_DEBUG;
-	else
-		log_level = IGT_LOG_CRITICAL;
-
-	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
-		"sampling rate %d Hz and %d channels: %s\n",
-		state->name, snd_pcm_format_name(state->playback.format),
-		state->playback.rate, state->playback.channels,
-		success ? "ALL GREEN" : "FAILED");
-
-}
-
-static void check_audio_infoframe(struct audio_state *state)
-{
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_audio infoframe_audio;
-	struct infoframe_audio expected = {0};
-	bool ok;
-
-	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
-		igt_debug("Skipping audio InfoFrame check: "
-			  "Chamelium board doesn't support GetLastInfoFrame\n");
-		return;
-	}
-
-	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
-	expected.channel_count = state->playback.channels;
-	expected.sampling_freq = state->playback.rate;
-	expected.sample_size = snd_pcm_format_width(state->playback.format);
-
-	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
-						 CHAMELIUM_INFOFRAME_AUDIO);
-	if (infoframe == NULL && state->playback.channels <= 2) {
-		/* Audio InfoFrames are optional for mono and stereo audio */
-		igt_debug("Skipping audio InfoFrame check: "
-			  "no InfoFrame received\n");
-		return;
-	}
-	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
-
-	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
-				   infoframe->payload, infoframe->payload_size);
-	chamelium_infoframe_destroy(infoframe);
-	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
-
-	igt_debug("Checking audio InfoFrame:\n");
-	igt_debug("coding_type: got %d, expected %d\n",
-		  infoframe_audio.coding_type, expected.coding_type);
-	igt_debug("channel_count: got %d, expected %d\n",
-		  infoframe_audio.channel_count, expected.channel_count);
-	igt_debug("sampling_freq: got %d, expected %d\n",
-		  infoframe_audio.sampling_freq, expected.sampling_freq);
-	igt_debug("sample_size: got %d, expected %d\n",
-		  infoframe_audio.sample_size, expected.sample_size);
-
-	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
-		igt_assert(infoframe_audio.coding_type == expected.coding_type);
-	if (infoframe_audio.channel_count >= 0)
-		igt_assert(infoframe_audio.channel_count == expected.channel_count);
-	if (infoframe_audio.sampling_freq >= 0)
-		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
-	if (infoframe_audio.sample_size >= 0)
-		igt_assert(infoframe_audio.sample_size == expected.sample_size);
-}
-
-static int
-audio_output_frequencies_callback(void *data, void *buffer, int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	audio_signal_fill(state->signal, tmp, samples);
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool test_audio_frequencies(struct audio_state *state)
-{
-	int freq, step;
-	int32_t *recv, *buf;
-	double *channel;
-	size_t i, j, streak;
-	size_t recv_len, buf_len, buf_cap, channel_len;
-	bool success;
-	int capture_chan;
-
-	state->signal = audio_signal_init(state->playback.channels,
-					  state->playback.rate);
-	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
-
-	/* We'll choose different frequencies per channel to make sure they are
-	 * independent from each other. To do so, we'll add a different offset
-	 * to the base frequencies for each channel. We need to choose a big
-	 * enough offset so that we're sure to detect mixed up channels. We
-	 * choose an offset of two 2 bins in the final FFT to enforce a clear
-	 * difference.
-	 *
-	 * Note that we assume capture_rate == playback_rate. We'll assert this
-	 * later on. We cannot retrieve the capture rate before starting
-	 * playing audio, so we don't really have the choice.
-	 */
-	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
-	for (i = 0; i < test_frequencies_count; i++) {
-		for (j = 0; j < state->playback.channels; j++) {
-			freq = test_frequencies[i] + j * step;
-			audio_signal_add_frequency(state->signal, freq, j);
-		}
-	}
-	audio_signal_synthesize(state->signal);
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_frequencies_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	audio_state_start(state, "frequencies");
-
-	igt_assert_f(state->capture.rate == state->playback.rate,
-		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
-		     state->capture.rate, state->playback.rate);
-
-	/* Needs to be a multiple of 128, because that's the number of samples
-	 * we get per channel each time we receive an audio page from the
-	 * Chamelium device.
-	 *
-	 * Additionally, this value needs to be high enough to guarantee we
-	 * capture a full period of each sine we generate. If we capture 2048
-	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
-	 * sines. For lower sampling rates, the capture duration will be
-	 * longer.
-	 */
-	channel_len = CAPTURE_SAMPLES;
-	channel = malloc(sizeof(double) * channel_len);
-
-	buf_cap = state->capture.channels * channel_len;
-	buf = malloc(sizeof(int32_t) * buf_cap);
-	buf_len = 0;
-
-	recv = NULL;
-	recv_len = 0;
-
-	success = false;
-	streak = 0;
-	while (!success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
-		buf_len += recv_len;
-
-		if (buf_len < buf_cap)
-			continue;
-		igt_assert(buf_len == buf_cap);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (j = 0; j < state->playback.channels; j++) {
-			capture_chan = state->channel_mapping[j];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", j, capture_chan);
-
-			audio_extract_channel_s32_le(channel, channel_len,
-						     buf, buf_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			if (audio_signal_detect(state->signal,
-						state->capture.rate, j,
-						channel, channel_len))
-				streak++;
-			else
-				streak = 0;
-		}
-
-		buf_len = 0;
-
-		success = streak == MIN_STREAK * state->playback.channels;
-	}
-
-	audio_state_stop(state, success);
-
-	free(recv);
-	free(buf);
-	free(channel);
-	audio_signal_fini(state->signal);
-
-	check_audio_infoframe(state);
-
-	return success;
-}
-
-static int audio_output_flatline_callback(void *data, void *buffer,
-					     int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len, i;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	for (i = 0; i < len; i++)
-		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
-{
-	double expected, min, max;
-	size_t i;
-	bool ok;
-
-	min = max = NAN;
-	for (i = 0; i < buf_len; i++) {
-		if (isnan(min) || buf[i] < min)
-			min = buf[i];
-		if (isnan(max) || buf[i] > max)
-			max = buf[i];
-	}
-
-	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
-	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
-	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
-	if (ok)
-		igt_debug("Flatline wave amplitude detected\n");
-	else
-		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
-			  min, max);
-	return ok;
-}
-
-static ssize_t detect_falling_edge(double *buf, size_t buf_len)
-{
-	size_t i;
-
-	for (i = 0; i < buf_len; i++) {
-		if (buf[i] < 0)
-			return i;
-	}
-
-	return -1;
-}
-
-/** test_audio_flatline:
- *
- * Send a constant value (one positive, then a negative one) and check that:
- *
- * - The amplitude of the flatline is correct
- * - All channels switch from a positive signal to a negative one at the same
- *   time (ie. all channels are aligned)
- */
-static bool test_audio_flatline(struct audio_state *state)
-{
-	bool success, amp_success, align_success;
-	int32_t *recv;
-	size_t recv_len, i, channel_len;
-	ssize_t j;
-	int streak, capture_chan;
-	double *channel;
-	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_flatline_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	/* Start by sending a positive signal */
-	state->positive = true;
-
-	audio_state_start(state, "flatline");
-
-	for (i = 0; i < state->playback.channels; i++)
-		falling_edges[i] = -1;
-
-	recv = NULL;
-	recv_len = 0;
-	amp_success = false;
-	streak = 0;
-	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (i = 0; i < state->playback.channels; i++) {
-			capture_chan = state->channel_mapping[i];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", i, capture_chan);
-
-			channel_len = audio_extract_channel_s32_le(NULL, 0,
-								   recv, recv_len,
-								   state->capture.channels,
-								   capture_chan);
-			channel = malloc(channel_len * sizeof(double));
-			audio_extract_channel_s32_le(channel, channel_len,
-						     recv, recv_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			/* Check whether the amplitude is fine */
-			if (detect_flatline_amplitude(channel, channel_len,
-						      state->positive))
-				streak++;
-			else
-				streak = 0;
-
-			/* If we're now sending a negative signal, detect the
-			 * falling edge */
-			j = detect_falling_edge(channel, channel_len);
-			if (!state->positive && j >= 0) {
-				falling_edges[i] = recv_len * state->recv_pages
-						   + j;
-			}
-
-			free(channel);
-		}
-
-		amp_success = streak == MIN_STREAK * state->playback.channels;
-
-		if (amp_success && state->positive) {
-			/* Switch to a negative signal after we've detected the
-			 * positive one. */
-			state->positive = false;
-			amp_success = false;
-			streak = 0;
-			igt_debug("Switching to negative square wave\n");
-		}
-	}
-
-	/* Check alignment between all channels by comparing the index of the
-	 * falling edge. */
-	align_success = true;
-	for (i = 0; i < state->playback.channels; i++) {
-		if (falling_edges[i] < 0) {
-			igt_critical("Falling edge not detected for channel %zu\n",
-				     i);
-			align_success = false;
-			continue;
-		}
-
-		if (abs(falling_edges[0] - falling_edges[i]) >
-		    FLATLINE_ALIGN_ACCURACY) {
-			igt_critical("Channel alignment mismatch: "
-				     "channel 0 has a falling edge at index %d "
-				     "while channel %zu has index %d\n",
-				     falling_edges[0], i, falling_edges[i]);
-			align_success = false;
-		}
-	}
-
-	success = amp_success && align_success;
-	audio_state_stop(state, success);
-
-	free(recv);
-
-	return success;
-}
-
-static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
-				      int channels, int sampling_rate)
-{
-	if (!alsa_test_output_configuration(alsa, format, channels,
-					    sampling_rate)) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because at least one of the "
-			  "selected output devices doesn't support this "
-			  "configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	/* TODO: the Chamelium device sends a malformed signal for some audio
-	 * configurations. See crbug.com/950917 */
-	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
-			channels > 2) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because the Chamelium device "
-			  "doesn't support this configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	return true;
-}
-
-static const char test_display_audio_desc[] =
-	"Playback various audio signals with various audio formats/rates, "
-	"capture them and check they are correct";
-static void
-test_display_audio(data_t *data, struct chamelium_port *port,
-		   const char *audio_device, enum igt_custom_edid_type edid)
-{
-	bool run, success;
-	struct alsa *alsa;
-	int ret;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j;
-	int channels, sampling_rate;
-	snd_pcm_format_t format;
-	struct audio_state state;
-
-	igt_require(alsa_has_exclusive_access());
-
-	/* Old Chamelium devices need an update for DisplayPort audio and
-	 * chamelium_get_audio_format support. */
-	igt_require(chamelium_has_audio_support(data->chamelium, port));
-
-	alsa = alsa_init();
-	igt_assert(alsa);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because the receiver won't try to receive audio if
-	 * it doesn't receive video. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	run = false;
-	success = true;
-	for (i = 0; i < test_sampling_rates_count; i++) {
-		for (j = 0; j < test_formats_count; j++) {
-			ret = alsa_open_output(alsa, audio_device);
-			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
-
-			/* TODO: playback on all 8 available channels (this
-			 * isn't supported by Chamelium devices yet, see
-			 * https://crbug.com/950917) */
-			format = test_formats[j];
-			channels = PLAYBACK_CHANNELS;
-			sampling_rate = test_sampling_rates[i];
-
-			if (!check_audio_configuration(alsa, format, channels,
-						       sampling_rate))
-				continue;
-
-			run = true;
-
-			audio_state_init(&state, data, alsa, port,
-					 format, channels, sampling_rate);
-			success &= test_audio_frequencies(&state);
-			success &= test_audio_flatline(&state);
-			audio_state_fini(&state);
-
-			alsa_close_output(alsa);
-		}
-	}
-
-	/* Make sure we tested at least one frequency and format. */
-	igt_assert(run);
-	/* Make sure all runs were successful. */
-	igt_assert(success);
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-
-	free(alsa);
-}
-
-static const char test_display_audio_edid_desc[] =
-	"Plug a connector with an EDID suitable for audio, check ALSA's "
-	"EDID-Like Data reports the correct audio parameters";
-static void
-test_display_audio_edid(data_t *data, struct chamelium_port *port,
-			enum igt_custom_edid_type edid)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id;
-	struct eld_entry eld;
-	struct eld_sad *sad;
-
-	igt_require(eld_is_supported());
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because audio cannot be played on inactive
-	 * connectors. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	igt_assert(eld_get_igt(&eld));
-	igt_assert(eld.sads_len == 1);
-
-	sad = &eld.sads[0];
-	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
-	igt_assert(sad->channels == 2);
-	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
-		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
-	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
-		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-}
-
-static void randomize_plane_stride(data_t *data,
-				   uint32_t width, uint32_t height,
-				   uint32_t format, uint64_t modifier,
-				   size_t *stride)
-{
-	size_t stride_min;
-	uint32_t max_tile_w = 4, tile_w, tile_h;
-	int i;
-	struct igt_fb dummy;
-
-	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
-
-	/* Randomize the stride to less than twice the minimum. */
-	*stride = (rand() % stride_min) + stride_min;
-
-	/*
-	 * Create a dummy FB to determine bpp for each plane, and calculate
-	 * the maximum tile width from that.
-	 */
-	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
-	for (i = 0; i < dummy.num_planes; i++) {
-		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
-
-		if (tile_w > max_tile_w)
-			max_tile_w = tile_w;
-	}
-	igt_remove_fb(data->drm_fd, &dummy);
-
-	/*
-	 * Pixman requires the stride to be aligned to 32-bits, which is
-	 * reflected in the initial value of max_tile_w and the hw
-	 * may require a multiple of tile width, choose biggest of the 2.
-	 */
-	*stride = ALIGN(*stride, max_tile_w);
-}
-
-static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
-				  uint32_t height, uint32_t format,
-				  uint64_t *modifier)
-{
-	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
-		/* Randomize the column height to less than twice the minimum. */
-		size_t column_height = (rand() % height) + height;
-
-		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
-			  column_height);
-
-		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
-	}
-}
-
-static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
-				  drmModeModeInfo *mode,
-				  uint32_t *width, uint32_t *height,
-				  uint32_t *format, uint64_t *modifier,
-				  bool allow_yuv)
-{
-	int min_dim;
-	uint32_t idx[plane->format_mod_count];
-	unsigned int count = 0;
-	unsigned int i;
-
-	/* First pass to count the supported formats. */
-	for (i = 0; i < plane->format_mod_count; i++)
-		if (igt_fb_supported_format(plane->formats[i]) &&
-		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
-			idx[count++] = i;
-
-	igt_assert(count > 0);
-
-	i = idx[rand() % count];
-	*format = plane->formats[i];
-	*modifier = plane->modifiers[i];
-
-	update_tiled_modifier(plane, *width, *height, *format, modifier);
-
-	/*
-	 * Randomize width and height in the mode dimensions range.
-	 *
-	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
-	 * least min_dim, because src_w = width - (rand % w / 2).
-	 *
-	 * Use a minimum dimension of 16 for YUV, because planar YUV
-	 * subsamples the UV plane.
-	 */
-	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
-
-	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
-	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
-}
-
-static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
-			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
-			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
-			    struct igt_fb *fb)
-{
-	igt_plane_set_fb(plane, fb);
-
-	igt_plane_set_position(plane, crtc_x, crtc_y);
-	igt_plane_set_size(plane, crtc_w, crtc_h);
-
-	igt_fb_set_position(fb, plane, src_x, src_y);
-	igt_fb_set_size(fb, plane, src_w, src_h);
-}
-
-static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
-					drmModeModeInfo *mode,
-					struct igt_fb *fb,
-					uint32_t *src_w, uint32_t *src_h,
-					uint32_t *src_x, uint32_t *src_y,
-					uint32_t *crtc_w, uint32_t *crtc_h,
-					int32_t *crtc_x, int32_t *crtc_y,
-					bool allow_scaling)
-{
-	bool is_yuv = igt_format_is_yuv(fb->drm_format);
-	uint32_t width = fb->width, height = fb->height;
-	double ratio;
-	int ret;
-
-	/* Randomize source offset in the first half of the original size. */
-	*src_x = rand() % (width / 2);
-	*src_y = rand() % (height / 2);
-
-	/* The source size only includes the active source area. */
-	*src_w = width - *src_x;
-	*src_h = height - *src_y;
-
-	if (allow_scaling) {
-		*crtc_w = (rand() % mode->hdisplay) + 1;
-		*crtc_h = (rand() % mode->vdisplay) + 1;
-
-		/*
-		 * Don't bother with scaling if dimensions are quite close in
-		 * order to get non-scaling cases more frequently. Also limit
-		 * scaling to 3x to avoid agressive filtering that makes
-		 * comparison less reliable, and don't go above 2x downsampling
-		 * to avoid possible hw limitations.
-		 */
-
-		ratio = ((double) *crtc_w / *src_w);
-		if (ratio < 0.5)
-			*src_w = *crtc_w * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_w = *src_w;
-		else if (ratio > 3.0)
-			*crtc_w = *src_w * 3;
-
-		ratio = ((double) *crtc_h / *src_h);
-		if (ratio < 0.5)
-			*src_h = *crtc_h * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_h = *src_h;
-		else if (ratio > 3.0)
-			*crtc_h = *src_h * 3;
-	} else {
-		*crtc_w = *src_w;
-		*crtc_h = *src_h;
-	}
-
-	if (*crtc_w != *src_w || *crtc_h != *src_h) {
-		/*
-		 * When scaling is involved, make sure to not go off-bounds or
-		 * scaled clipping may result in decimal dimensions, that most
-		 * drivers don't support.
-		 */
-		if (*crtc_w < mode->hdisplay)
-			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
-		else
-			*crtc_x = 0;
-
-		if (*crtc_h < mode->vdisplay)
-			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
-		else
-			*crtc_y = 0;
-	} else {
-		/*
-		 * Randomize the on-crtc position and allow the plane to go
-		 * off-display by less than half of its on-crtc dimensions.
-		 */
-		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
-		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
-	}
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
-			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
-	ret = igt_display_try_commit_atomic(&data->display,
-					    DRM_MODE_ATOMIC_TEST_ONLY |
-					    DRM_MODE_ATOMIC_ALLOW_MODESET,
-					    NULL);
-	if (!ret)
-		return;
-
-	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
-	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
-
-	/* Make YUV coordinates a multiple of 2 and retry the math. */
-	if (is_yuv) {
-		*src_x &= ~1;
-		*src_y &= ~1;
-		*src_w &= ~1;
-		*src_h &= ~1;
-		/* To handle 1:1 scaling, clear crtc_w/h too. */
-		*crtc_w &= ~1;
-		*crtc_h &= ~1;
-
-		if (*crtc_x < 0 && (*crtc_x & 1))
-			(*crtc_x)++;
-		else
-			*crtc_x &= ~1;
-
-		/* If negative, round up to 0 instead of down */
-		if (*crtc_y < 0 && (*crtc_y & 1))
-			(*crtc_y)++;
-		else
-			*crtc_y &= ~1;
-
-		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-				*crtc_h, *crtc_x, *crtc_y, fb);
-		ret = igt_display_try_commit_atomic(&data->display,
-						DRM_MODE_ATOMIC_TEST_ONLY |
-						DRM_MODE_ATOMIC_ALLOW_MODESET,
-						NULL);
-		if (!ret)
-			return;
-	}
-
-	igt_assert(!ret || allow_scaling);
-	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
-		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
-
-	*crtc_w = *src_w;
-	*crtc_h = *src_h;
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-			*crtc_h, *crtc_x, *crtc_y, fb);
-	igt_display_commit_atomic(&data->display,
-				  DRM_MODE_ATOMIC_TEST_ONLY |
-				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-}
-
-static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
-			     uint32_t src_w, uint32_t src_h,
-			     uint32_t src_x, uint32_t src_y,
-			     uint32_t crtc_w, uint32_t crtc_h,
-			     int32_t crtc_x, int32_t crtc_y,
-			     struct igt_fb *fb)
-{
-	cairo_surface_t *surface;
-	cairo_surface_t *clipped_surface;
-	cairo_t *cr;
-
-	surface = igt_get_cairo_surface(data->drm_fd, fb);
-
-	if (src_x || src_y) {
-		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
-							     src_w, src_h);
-
-		cr = cairo_create(clipped_surface);
-
-		cairo_translate(cr, -1. * src_x, -1. * src_y);
-
-		cairo_set_source_surface(cr, surface, 0, 0);
-
-		cairo_paint(cr);
-		cairo_surface_flush(clipped_surface);
-
-		cairo_destroy(cr);
-	} else {
-		clipped_surface = surface;
-	}
-
-	cr = cairo_create(result);
-
-	cairo_translate(cr, crtc_x, crtc_y);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_scale(cr, (double) crtc_w / src_w,
-			    (double) crtc_h / src_h);
-	}
-
-	cairo_set_source_surface(cr, clipped_surface, 0, 0);
-	cairo_surface_destroy(clipped_surface);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_pattern_set_filter(cairo_get_source(cr),
-					 CAIRO_FILTER_BILINEAR);
-		cairo_pattern_set_extend(cairo_get_source(cr),
-					 CAIRO_EXTEND_NONE);
-	}
-
-	cairo_paint(cr);
-	cairo_surface_flush(result);
-
-	cairo_destroy(cr);
-}
-
-static void prepare_randomized_plane(data_t *data,
-				     drmModeModeInfo *mode,
-				     igt_plane_t *plane,
-				     struct igt_fb *overlay_fb,
-				     unsigned int index,
-				     cairo_surface_t *result_surface,
-				     bool allow_scaling, bool allow_yuv)
-{
-	struct igt_fb pattern_fb;
-	uint32_t overlay_fb_w, overlay_fb_h;
-	uint32_t overlay_src_w, overlay_src_h;
-	uint32_t overlay_src_x, overlay_src_y;
-	int32_t overlay_crtc_x, overlay_crtc_y;
-	uint32_t overlay_crtc_w, overlay_crtc_h;
-	uint32_t format;
-	uint64_t modifier;
-	size_t stride;
-	bool tiled;
-	int fb_id;
-
-	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
-			      &format, &modifier, allow_yuv);
-
-	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
-	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
-		  index, overlay_fb_w, overlay_fb_h,
-		  igt_format_str(format), tiled ? "tiled" : "linear");
-
-	/* Get a pattern framebuffer for the overlay plane. */
-	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
-					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
-			       format, modifier, &stride);
-
-	igt_debug("Plane %d: stride %ld\n", index, stride);
-
-	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
-					   modifier, stride);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_coordinates(data, plane, mode, overlay_fb,
-				    &overlay_src_w, &overlay_src_h,
-				    &overlay_src_x, &overlay_src_y,
-				    &overlay_crtc_w, &overlay_crtc_h,
-				    &overlay_crtc_x, &overlay_crtc_y,
-				    allow_scaling);
-
-	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
-		  overlay_src_w, overlay_src_h);
-	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
-		  overlay_src_x, overlay_src_y);
-	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
-		  overlay_crtc_w, overlay_crtc_h);
-	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
-		  overlay_crtc_x, overlay_crtc_y);
-
-	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
-			 overlay_src_x, overlay_src_y,
-			 overlay_crtc_w, overlay_crtc_h,
-			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
-
-	/* Remove the original pattern framebuffer. */
-	igt_remove_fb(data->drm_fd, &pattern_fb);
-}
-
-static const char test_display_planes_random_desc[] =
-	"Setup a few overlay planes with random parameters, capture the frame "
-	"and check it matches the expected output";
-static void test_display_planes_random(data_t *data,
-				       struct chamelium_port *port,
-				       enum chamelium_check check)
-{
-	igt_output_t *output;
-	drmModeModeInfo *mode;
-	igt_plane_t *primary_plane;
-	struct igt_fb primary_fb;
-	struct igt_fb result_fb;
-	struct igt_fb *overlay_fbs;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	unsigned int overlay_planes_max = 0;
-	unsigned int overlay_planes_count;
-	cairo_surface_t *result_surface;
-	int captured_frame_count;
-	bool allow_scaling;
-	bool allow_yuv;
-	unsigned int i;
-	unsigned int fb_id;
-
-	switch (check) {
-	case CHAMELIUM_CHECK_CRC:
-		allow_scaling = false;
-		allow_yuv = false;
-		break;
-	case CHAMELIUM_CHECK_CHECKERBOARD:
-		allow_scaling = true;
-		allow_yuv = true;
-		break;
-	default:
-		igt_assert(false);
-	}
-
-	srand(time(NULL));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Find the connector and pipe. */
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-
-	mode = igt_output_get_mode(output);
-
-	/* Get a framebuffer for the primary plane. */
-	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary_plane);
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
-	igt_assert(fb_id > 0);
-
-	/* Get a framebuffer for the cairo composition result. */
-	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
-			      mode->vdisplay, DRM_FORMAT_XRGB8888,
-			      DRM_FORMAT_MOD_LINEAR, &result_fb);
-	igt_assert(fb_id > 0);
-
-	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
-
-	/* Paint the primary framebuffer on the result surface. */
-	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
-			 &primary_fb);
-
-	/* Configure the primary plane. */
-	igt_plane_set_fb(primary_plane, &primary_fb);
-
-	overlay_planes_max =
-		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
-
-	/* Limit the number of planes to a reasonable scene. */
-	overlay_planes_max = min(overlay_planes_max, 4u);
-
-	overlay_planes_count = (rand() % overlay_planes_max) + 1;
-	igt_debug("Using %d overlay planes\n", overlay_planes_count);
-
-	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
-
-	for (i = 0; i < overlay_planes_count; i++) {
-		struct igt_fb *overlay_fb = &overlay_fbs[i];
-		igt_plane_t *plane =
-			igt_output_get_plane_type_index(output,
-							DRM_PLANE_TYPE_OVERLAY,
-							i);
-		igt_assert(plane);
-
-		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
-					 result_surface, allow_scaling,
-					 allow_yuv);
-	}
-
-	cairo_surface_destroy(result_surface);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&result_fb);
-
-	igt_display_commit2(&data->display, COMMIT_ATOMIC);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == 1);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium,
-						expected_crc, crc,
-						&result_fb, 0);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &result_fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	for (i = 0; i < overlay_planes_count; i++)
-		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
-
-	free(overlay_fbs);
-
-	igt_remove_fb(data->drm_fd, &primary_fb);
-	igt_remove_fb(data->drm_fd, &result_fb);
-}
-
-static const char test_hpd_without_ddc_desc[] =
-	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
-static void
-test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-	igt_flush_uevents(mon);
-
-	/* Disable the DDC on the connector and make sure we still get a
-	 * hotplug
-	 */
-	chamelium_port_set_ddc_state(data->chamelium, port, false);
-	chamelium_plug(data->chamelium, port);
-
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_assert_eq(chamelium_reprobe_connector(&data->display,
-						  data->chamelium, port),
-						  DRM_MODE_CONNECTED);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_hpd_storm_detect_desc[] =
-	"Trigger a series of hotplugs in a very small timeframe to simulate a"
-	"bad cable, check the kernel falls back to polling to avoid a hotplug "
-	"storm";
-static void
-test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
-{
-	struct udev_monitor *mon;
-	int count = 0;
-
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 1);
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-	igt_assert(igt_hpd_storm_detected(data->drm_fd));
-
-	mon = igt_watch_uevents();
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-
-	/*
-	 * Polling should have been enabled by the HPD storm at this point,
-	 * so we should only get at most 1 hotplug event
-	 */
-	igt_until_timeout(5)
-		count += igt_hotplug_detected(mon, 1);
-	igt_assert_lt(count, 2);
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_hpd_storm_disable_desc[] =
-	"Disable HPD storm detection, trigger a storm and check the kernel "
-	"doesn't detect one";
-static void
-test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
-{
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	chamelium_fire_hpd_pulses(data->chamelium, port,
-				  width, 10);
-	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
-
-	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,
-				   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;
-
-		monitor_edid *edid = &edids_list[i];
-		igt_info("Testing out the EDID for %s\n",
-			 monitor_edid_get_name(edid));
-
-		/* Getting and Setting the EDID on Chamelium. */
-		chamelium_edid =
-			get_chameleon_edid_from_monitor_edid(chamelium, 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);
-}
-
-static const char igt_edid_resolution_list_desc[] =
-	"Get an EDID with many modes of different configurations, set them on the screen and check the"
-	" screen resolution matches the mode resolution.";
-
-static void edid_resolution_list(data_t *data, struct chamelium_port *port)
-{
-	struct chamelium *chamelium = data->chamelium;
-	struct udev_monitor *mon = igt_watch_uevents();
-	drmModeConnector *connector;
-	drmModeModeInfoPtr modes;
-	int count_modes;
-	int i;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	chamelium_unplug(chamelium, port);
-	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
-
-	igt_flush_uevents(mon);
-	chamelium_plug(chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
-	igt_flush_uevents(mon);
-
-	connector = chamelium_port_get_connector(chamelium, port, true);
-	modes = connector->modes;
-	count_modes = connector->count_modes;
-
-	output = get_output_for_port(data, port);
-	pipe = get_pipe_for_output(&data->display, output);
-	igt_output_set_pipe(output, pipe);
-
-	for (i = 0; i < count_modes; ++i)
-		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
-
-	for (i = 0; i < count_modes; ++i) {
-		struct igt_fb fb = { 0 };
-		bool is_video_stable;
-		int screen_res_w, screen_res_h;
-
-		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
-			 modes[i].vrefresh);
-
-		/* Set the screen mode with the one we chose. */
-		create_fb_for_mode(data, &fb, &modes[i]);
-		enable_output(data, port, output, &modes[i], &fb);
-		is_video_stable = chamelium_port_wait_video_input_stable(
-			chamelium, port, 10);
-		igt_assert(is_video_stable);
-
-		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
-					      &screen_res_h);
-		igt_assert_eq(screen_res_w, modes[i].hdisplay);
-		igt_assert_eq(screen_res_h, modes[i].vdisplay);
-
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	drmModeFreeConnector(connector);
-}
-
-#define for_each_port(p, port)            \
-	for (p = 0, port = data.ports[p]; \
-	     p < data.port_count;         \
-	     p++, port = data.ports[p])
-
-#define connector_subtest(name__, type__)                    \
-	igt_subtest(name__)                                  \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-#define connector_dynamic_subtest(name__, type__)            \
-	igt_subtest_with_dynamic(name__)                     \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-
-static data_t data;
-
-IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
-igt_main
-{
-	struct chamelium_port *port;
-	int p;
-	size_t i;
-
-	igt_fixture {
-		/* So fbcon doesn't try to reprobe things itself */
-		kmstest_set_vt_graphics_mode();
-
-		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
-
-		/*
-		 * XXX: disabling modeset, can be removed when
-		 * igt_display_require will start doing this for us
-		 */
-		igt_display_commit2(&data.display, COMMIT_ATOMIC);
-
-		/* we need to initalize chamelium after igt_display_require */
-		data.chamelium = chamelium_init(data.drm_fd, &data.display);
-		igt_require(data.chamelium);
-
-		data.ports = chamelium_get_ports(data.chamelium,
-						 &data.port_count);
-
-		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
-			data.edids[i] = chamelium_new_edid(data.chamelium,
-							   igt_kms_get_custom_edid(i));
-		}
-	}
-
-	igt_describe("DisplayPort tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-fast", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("dp-edid-read", DisplayPort) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_4K,
-					       ARRAY_SIZE(DP_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-non-4k",
-				  DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
-					       ARRAY_SIZE(DP_EDIDS_NON_4K));
-
-		igt_describe(igt_edid_resolution_list_desc);
-		connector_subtest("dp-edid-resolution-list", DisplayPort)
-			edid_resolution_list(&data, port);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-suspend", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("dp-hpd-storm", DisplayPort)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("dp-hpd-storm-disable", DisplayPort)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("dp-crc-fast", DisplayPort)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("dp-frame-dump", DisplayPort)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("dp-mode-timings", DisplayPort)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("dp-audio", DisplayPort)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("dp-audio-edid", DisplayPort)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("HDMI tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-fast", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("hdmi-edid-read", HDMIA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("hdmi-hpd-storm", HDMIA)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("hdmi-crc-fast", HDMIA)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CRC, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-crc-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CRC);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (!igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-cmp-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CHECKERBOARD);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("hdmi-frame-dump", HDMIA)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("hdmi-mode-timings", HDMIA)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("hdmi-audio", HDMIA)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("hdmi-audio-edid", HDMIA)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_aspect_ratio_desc);
-		connector_subtest("hdmi-aspect-ratio", HDMIA)
-			test_display_aspect_ratio(&data, port);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("VGA tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-fast", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-enable-disable-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-with-enabled-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("vga-edid-read", VGA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-suspend", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-hibernate", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_without_ddc_desc);
-		connector_subtest("vga-hpd-without-ddc", VGA)
-			test_hpd_without_ddc(&data, port);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("vga-frame-dump", VGA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_ANALOG, 1);
-	}
-
-	igt_describe("Tests that operate on all connectors");
-	igt_subtest_group {
-
-		igt_fixture {
-			igt_require(data.port_count);
-		}
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-suspend")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_MEM,
-						       SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-hibernate")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_DISK,
-						       SUSPEND_TEST_DEVICES);
-	}
-
-	igt_describe(test_hotplug_for_each_pipe_desc);
-	connector_subtest("vga-hpd-for-each-pipe", VGA)
-		test_hotplug_for_each_pipe(&data, port);
-
-	igt_fixture {
-		igt_display_fini(&data.display);
-		close(data.drm_fd);
-	}
-}
diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
new file mode 100644
index 00000000..4d13744c
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_audio.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the Audio functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+/* Playback parameters control the audio signal we synthesize and send */
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_SAMPLES 1024
+
+/* Capture paremeters control the audio signal we receive */
+#define CAPTURE_SAMPLES 2048
+
+#define AUDIO_TIMEOUT 2000 /* ms */
+/* A streak of 3 gives confidence that the signal is good. */
+#define MIN_STREAK 3
+
+#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
+#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
+#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
+
+struct audio_state {
+	struct alsa *alsa;
+	struct chamelium *chamelium;
+	struct chamelium_port *port;
+	struct chamelium_stream *stream;
+
+	/* The capture format is only available after capture has started. */
+	struct {
+		snd_pcm_format_t format;
+		int channels;
+		int rate;
+	} playback, capture;
+
+	char *name;
+	struct audio_signal *signal; /* for frequencies test only */
+	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	size_t recv_pages;
+	int msec;
+
+	int dump_fd;
+	char *dump_path;
+
+	pthread_t thread;
+	atomic_bool run;
+	atomic_bool positive; /* for pulse test only */
+};
+
+/* TODO: enable >48KHz rates, these are not reliable */
+static int test_sampling_rates[] = {
+	32000, 44100, 48000,
+	/* 88200, */
+	/* 96000, */
+	/* 176400, */
+	/* 192000, */
+};
+
+static int test_sampling_rates_count =
+	sizeof(test_sampling_rates) / sizeof(int);
+
+/* Test frequencies (Hz): a sine signal will be generated for each.
+ *
+ * Depending on the sampling rate chosen, it might not be possible to properly
+ * detect the generated sine (see Nyquist–Shannon sampling theorem).
+ * Frequencies that can't be reliably detected will be automatically pruned in
+ * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
+ * tested with a 192KHz sampling rate.
+ */
+static int test_frequencies[] = {
+	300, 600, 1200, 10000, 80000,
+};
+
+static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
+
+static const snd_pcm_format_t test_formats[] = {
+	SND_PCM_FORMAT_S16_LE,
+	SND_PCM_FORMAT_S24_LE,
+	SND_PCM_FORMAT_S32_LE,
+};
+
+static const size_t test_formats_count =
+	sizeof(test_formats) / sizeof(test_formats[0]);
+
+static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
+			     struct alsa *alsa, struct chamelium_port *port,
+			     snd_pcm_format_t format, int channels, int rate)
+{
+	memset(state, 0, sizeof(*state));
+	state->dump_fd = -1;
+
+	state->alsa = alsa;
+	state->chamelium = data->chamelium;
+	state->port = port;
+
+	state->playback.format = format;
+	state->playback.channels = channels;
+	state->playback.rate = rate;
+
+	alsa_configure_output(alsa, format, channels, rate);
+
+	state->stream = chamelium_stream_init();
+	igt_assert_f(state->stream,
+		     "Failed to initialize Chamelium stream client\n");
+}
+
+static void audio_state_fini(struct audio_state *state)
+{
+	chamelium_stream_deinit(state->stream);
+	free(state->name);
+}
+
+static void *run_audio_thread(void *data)
+{
+	struct alsa *alsa = data;
+
+	alsa_run(alsa, -1);
+	return NULL;
+}
+
+static void audio_state_start(struct audio_state *state, const char *name)
+{
+	int ret;
+	bool ok;
+	size_t i, j;
+	enum chamelium_stream_realtime_mode stream_mode;
+	char dump_suffix[64];
+
+	free(state->name);
+	state->name = strdup(name);
+	state->recv_pages = 0;
+	state->msec = 0;
+
+	igt_debug("Starting %s test with playback format %s, "
+		  "sampling rate %d Hz and %d channels\n",
+		  name, snd_pcm_format_name(state->playback.format),
+		  state->playback.rate, state->playback.channels);
+
+	chamelium_start_capturing_audio(state->chamelium, state->port, false);
+
+	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
+	igt_assert_f(ok, "Failed to start streaming audio capture\n");
+
+	/* Start playing audio */
+	state->run = true;
+	ret = pthread_create(&state->thread, NULL, run_audio_thread,
+			     state->alsa);
+	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
+
+	/* The Chamelium device only supports this PCM format. */
+	state->capture.format = SND_PCM_FORMAT_S32_LE;
+
+	/* Only after we've started playing audio, we can retrieve the capture
+	 * format used by the Chamelium device. */
+	chamelium_get_audio_format(state->chamelium, state->port,
+				   &state->capture.rate,
+				   &state->capture.channels);
+	if (state->capture.rate == 0) {
+		igt_debug("Audio receiver doesn't indicate the capture "
+			  "sampling rate, assuming it's %d Hz\n",
+			  state->playback.rate);
+		state->capture.rate = state->playback.rate;
+	}
+
+	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
+					    state->channel_mapping);
+	/* Make sure we can capture all channels we send. */
+	for (i = 0; i < state->playback.channels; i++) {
+		ok = false;
+		for (j = 0; j < state->capture.channels; j++) {
+			if (state->channel_mapping[j] == i) {
+				ok = true;
+				break;
+			}
+		}
+		igt_assert_f(ok, "Cannot capture all channels\n");
+	}
+
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix),
+			 "capture-%s-%s-%dch-%dHz", name,
+			 snd_pcm_format_name(state->playback.format),
+			 state->playback.channels, state->playback.rate);
+
+		state->dump_fd = audio_create_wav_file_s32_le(
+			dump_suffix, state->capture.rate,
+			state->capture.channels, &state->dump_path);
+		igt_assert_f(state->dump_fd >= 0,
+			     "Failed to create audio dump file\n");
+	}
+}
+
+static void audio_state_receive(struct audio_state *state, int32_t **recv,
+				size_t *recv_len)
+{
+	bool ok;
+	size_t page_count;
+	size_t recv_size;
+
+	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
+						     recv, recv_len);
+	igt_assert_f(ok, "Failed to receive audio from stream server\n");
+
+	state->msec = state->recv_pages * *recv_len /
+		      (double)state->capture.channels /
+		      (double)state->capture.rate * 1000;
+	state->recv_pages++;
+
+	if (state->dump_fd >= 0) {
+		recv_size = *recv_len * sizeof(int32_t);
+		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
+				     recv_size,
+			     "Failed to write to audio dump file\n");
+	}
+}
+
+static void audio_state_stop(struct audio_state *state, bool success)
+{
+	bool ok;
+	int ret;
+	struct chamelium_audio_file *audio_file;
+	enum igt_log_level log_level;
+
+	igt_debug("Stopping audio playback\n");
+	state->run = false;
+	ret = pthread_join(state->thread, NULL);
+	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
+
+	ok = chamelium_stream_stop_realtime_audio(state->stream);
+	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
+
+	audio_file =
+		chamelium_stop_capturing_audio(state->chamelium, state->port);
+	if (audio_file) {
+		igt_debug("Audio file saved on the Chamelium in %s\n",
+			  audio_file->path);
+		chamelium_destroy_audio_file(audio_file);
+	}
+
+	if (state->dump_fd >= 0) {
+		close(state->dump_fd);
+		state->dump_fd = -1;
+
+		if (success) {
+			/* Test succeeded, no need to keep the captured data */
+			unlink(state->dump_path);
+		} else
+			igt_debug("Saved captured audio data to %s\n",
+				  state->dump_path);
+		free(state->dump_path);
+		state->dump_path = NULL;
+	}
+
+	if (success)
+		log_level = IGT_LOG_DEBUG;
+	else
+		log_level = IGT_LOG_CRITICAL;
+
+	igt_log(IGT_LOG_DOMAIN, log_level,
+		"Audio %s test result for format %s, "
+		"sampling rate %d Hz and %d channels: %s\n",
+		state->name, snd_pcm_format_name(state->playback.format),
+		state->playback.rate, state->playback.channels,
+		success ? "ALL GREEN" : "FAILED");
+}
+
+static void check_audio_infoframe(struct audio_state *state)
+{
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_audio infoframe_audio;
+	struct infoframe_audio expected = { 0 };
+	bool ok;
+
+	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
+		igt_debug("Skipping audio InfoFrame check: "
+			  "Chamelium board doesn't support GetLastInfoFrame\n");
+		return;
+	}
+
+	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
+	expected.channel_count = state->playback.channels;
+	expected.sampling_freq = state->playback.rate;
+	expected.sample_size = snd_pcm_format_width(state->playback.format);
+
+	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
+						 CHAMELIUM_INFOFRAME_AUDIO);
+	if (infoframe == NULL && state->playback.channels <= 2) {
+		/* Audio InfoFrames are optional for mono and stereo audio */
+		igt_debug("Skipping audio InfoFrame check: "
+			  "no InfoFrame received\n");
+		return;
+	}
+	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
+
+	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
+				   infoframe->payload, infoframe->payload_size);
+	chamelium_infoframe_destroy(infoframe);
+	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
+
+	igt_debug("Checking audio InfoFrame:\n");
+	igt_debug("coding_type: got %d, expected %d\n",
+		  infoframe_audio.coding_type, expected.coding_type);
+	igt_debug("channel_count: got %d, expected %d\n",
+		  infoframe_audio.channel_count, expected.channel_count);
+	igt_debug("sampling_freq: got %d, expected %d\n",
+		  infoframe_audio.sampling_freq, expected.sampling_freq);
+	igt_debug("sample_size: got %d, expected %d\n",
+		  infoframe_audio.sample_size, expected.sample_size);
+
+	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
+		igt_assert(infoframe_audio.coding_type == expected.coding_type);
+	if (infoframe_audio.channel_count >= 0)
+		igt_assert(infoframe_audio.channel_count ==
+			   expected.channel_count);
+	if (infoframe_audio.sampling_freq >= 0)
+		igt_assert(infoframe_audio.sampling_freq ==
+			   expected.sampling_freq);
+	if (infoframe_audio.sample_size >= 0)
+		igt_assert(infoframe_audio.sample_size == expected.sample_size);
+}
+
+static int audio_output_frequencies_callback(void *data, void *buffer,
+					     int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	audio_signal_fill(state->signal, tmp, samples);
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool test_audio_frequencies(struct audio_state *state)
+{
+	int freq, step;
+	int32_t *recv, *buf;
+	double *channel;
+	size_t i, j, streak;
+	size_t recv_len, buf_len, buf_cap, channel_len;
+	bool success;
+	int capture_chan;
+
+	state->signal = audio_signal_init(state->playback.channels,
+					  state->playback.rate);
+	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
+
+	/* We'll choose different frequencies per channel to make sure they are
+	 * independent from each other. To do so, we'll add a different offset
+	 * to the base frequencies for each channel. We need to choose a big
+	 * enough offset so that we're sure to detect mixed up channels. We
+	 * choose an offset of two 2 bins in the final FFT to enforce a clear
+	 * difference.
+	 *
+	 * Note that we assume capture_rate == playback_rate. We'll assert this
+	 * later on. We cannot retrieve the capture rate before starting
+	 * playing audio, so we don't really have the choice.
+	 */
+	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
+	for (i = 0; i < test_frequencies_count; i++) {
+		for (j = 0; j < state->playback.channels; j++) {
+			freq = test_frequencies[i] + j * step;
+			audio_signal_add_frequency(state->signal, freq, j);
+		}
+	}
+	audio_signal_synthesize(state->signal);
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_frequencies_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	audio_state_start(state, "frequencies");
+
+	igt_assert_f(state->capture.rate == state->playback.rate,
+		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
+		     state->capture.rate, state->playback.rate);
+
+	/* Needs to be a multiple of 128, because that's the number of samples
+	 * we get per channel each time we receive an audio page from the
+	 * Chamelium device.
+	 *
+	 * Additionally, this value needs to be high enough to guarantee we
+	 * capture a full period of each sine we generate. If we capture 2048
+	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
+	 * sines. For lower sampling rates, the capture duration will be
+	 * longer.
+	 */
+	channel_len = CAPTURE_SAMPLES;
+	channel = malloc(sizeof(double) * channel_len);
+
+	buf_cap = state->capture.channels * channel_len;
+	buf = malloc(sizeof(int32_t) * buf_cap);
+	buf_len = 0;
+
+	recv = NULL;
+	recv_len = 0;
+
+	success = false;
+	streak = 0;
+	while (!success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
+		buf_len += recv_len;
+
+		if (buf_len < buf_cap)
+			continue;
+		igt_assert(buf_len == buf_cap);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (j = 0; j < state->playback.channels; j++) {
+			capture_chan = state->channel_mapping[j];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  j, capture_chan);
+
+			audio_extract_channel_s32_le(channel, channel_len, buf,
+						     buf_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			if (audio_signal_detect(state->signal,
+						state->capture.rate, j, channel,
+						channel_len))
+				streak++;
+			else
+				streak = 0;
+		}
+
+		buf_len = 0;
+
+		success = streak == MIN_STREAK * state->playback.channels;
+	}
+
+	audio_state_stop(state, success);
+
+	free(recv);
+	free(buf);
+	free(channel);
+	audio_signal_fini(state->signal);
+
+	check_audio_infoframe(state);
+
+	return success;
+}
+
+static int audio_output_flatline_callback(void *data, void *buffer, int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len, i;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	for (i = 0; i < len; i++)
+		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
+{
+	double expected, min, max;
+	size_t i;
+	bool ok;
+
+	min = max = NAN;
+	for (i = 0; i < buf_len; i++) {
+		if (isnan(min) || buf[i] < min)
+			min = buf[i];
+		if (isnan(max) || buf[i] > max)
+			max = buf[i];
+	}
+
+	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
+	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
+	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
+	if (ok)
+		igt_debug("Flatline wave amplitude detected\n");
+	else
+		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
+			  min, max);
+	return ok;
+}
+
+static ssize_t detect_falling_edge(double *buf, size_t buf_len)
+{
+	size_t i;
+
+	for (i = 0; i < buf_len; i++) {
+		if (buf[i] < 0)
+			return i;
+	}
+
+	return -1;
+}
+
+/** test_audio_flatline:
+ *
+ * Send a constant value (one positive, then a negative one) and check that:
+ *
+ * - The amplitude of the flatline is correct
+ * - All channels switch from a positive signal to a negative one at the same
+ *   time (ie. all channels are aligned)
+ */
+static bool test_audio_flatline(struct audio_state *state)
+{
+	bool success, amp_success, align_success;
+	int32_t *recv;
+	size_t recv_len, i, channel_len;
+	ssize_t j;
+	int streak, capture_chan;
+	double *channel;
+	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_flatline_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	/* Start by sending a positive signal */
+	state->positive = true;
+
+	audio_state_start(state, "flatline");
+
+	for (i = 0; i < state->playback.channels; i++)
+		falling_edges[i] = -1;
+
+	recv = NULL;
+	recv_len = 0;
+	amp_success = false;
+	streak = 0;
+	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (i = 0; i < state->playback.channels; i++) {
+			capture_chan = state->channel_mapping[i];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  i, capture_chan);
+
+			channel_len = audio_extract_channel_s32_le(
+				NULL, 0, recv, recv_len,
+				state->capture.channels, capture_chan);
+			channel = malloc(channel_len * sizeof(double));
+			audio_extract_channel_s32_le(channel, channel_len, recv,
+						     recv_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			/* Check whether the amplitude is fine */
+			if (detect_flatline_amplitude(channel, channel_len,
+						      state->positive))
+				streak++;
+			else
+				streak = 0;
+
+			/* If we're now sending a negative signal, detect the
+			 * falling edge */
+			j = detect_falling_edge(channel, channel_len);
+			if (!state->positive && j >= 0) {
+				falling_edges[i] =
+					recv_len * state->recv_pages + j;
+			}
+
+			free(channel);
+		}
+
+		amp_success = streak == MIN_STREAK * state->playback.channels;
+
+		if (amp_success && state->positive) {
+			/* Switch to a negative signal after we've detected the
+			 * positive one. */
+			state->positive = false;
+			amp_success = false;
+			streak = 0;
+			igt_debug("Switching to negative square wave\n");
+		}
+	}
+
+	/* Check alignment between all channels by comparing the index of the
+	 * falling edge. */
+	align_success = true;
+	for (i = 0; i < state->playback.channels; i++) {
+		if (falling_edges[i] < 0) {
+			igt_critical(
+				"Falling edge not detected for channel %zu\n",
+				i);
+			align_success = false;
+			continue;
+		}
+
+		if (abs(falling_edges[0] - falling_edges[i]) >
+		    FLATLINE_ALIGN_ACCURACY) {
+			igt_critical("Channel alignment mismatch: "
+				     "channel 0 has a falling edge at index %d "
+				     "while channel %zu has index %d\n",
+				     falling_edges[0], i, falling_edges[i]);
+			align_success = false;
+		}
+	}
+
+	success = amp_success && align_success;
+	audio_state_stop(state, success);
+
+	free(recv);
+
+	return success;
+}
+
+static bool check_audio_configuration(struct alsa *alsa,
+				      snd_pcm_format_t format, int channels,
+				      int sampling_rate)
+{
+	if (!alsa_test_output_configuration(alsa, format, channels,
+					    sampling_rate)) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because at least one of the "
+			  "selected output devices doesn't support this "
+			  "configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	/* TODO: the Chamelium device sends a malformed signal for some audio
+	 * configurations. See crbug.com/950917 */
+	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
+	    channels > 2) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because the Chamelium device "
+			  "doesn't support this configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	return true;
+}
+
+static const char test_display_audio_desc[] =
+	"Playback various audio signals with various audio formats/rates, "
+	"capture them and check they are correct";
+static void test_display_audio(chamelium_data_t *data,
+			       struct chamelium_port *port,
+			       const char *audio_device,
+			       enum igt_custom_edid_type edid)
+{
+	bool run, success;
+	struct alsa *alsa;
+	int ret;
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id, i, j;
+	int channels, sampling_rate;
+	snd_pcm_format_t format;
+	struct audio_state state;
+
+	igt_require(alsa_has_exclusive_access());
+
+	/* Old Chamelium devices need an update for DisplayPort audio and
+	 * chamelium_get_audio_format support. */
+	igt_require(chamelium_has_audio_support(data->chamelium, port));
+
+	alsa = alsa_init();
+	igt_assert(alsa);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because the receiver won't try to receive audio if
+	 * it doesn't receive video. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	run = false;
+	success = true;
+	for (i = 0; i < test_sampling_rates_count; i++) {
+		for (j = 0; j < test_formats_count; j++) {
+			ret = alsa_open_output(alsa, audio_device);
+			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
+
+			/* TODO: playback on all 8 available channels (this
+			 * isn't supported by Chamelium devices yet, see
+			 * https://crbug.com/950917) */
+			format = test_formats[j];
+			channels = PLAYBACK_CHANNELS;
+			sampling_rate = test_sampling_rates[i];
+
+			if (!check_audio_configuration(alsa, format, channels,
+						       sampling_rate))
+				continue;
+
+			run = true;
+
+			audio_state_init(&state, data, alsa, port, format,
+					 channels, sampling_rate);
+			success &= test_audio_frequencies(&state);
+			success &= test_audio_flatline(&state);
+			audio_state_fini(&state);
+
+			alsa_close_output(alsa);
+		}
+	}
+
+	/* Make sure we tested at least one frequency and format. */
+	igt_assert(run);
+	/* Make sure all runs were successful. */
+	igt_assert(success);
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+
+	free(alsa);
+}
+
+static const char test_display_audio_edid_desc[] =
+	"Plug a connector with an EDID suitable for audio, check ALSA's "
+	"EDID-Like Data reports the correct audio parameters";
+static void test_display_audio_edid(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_custom_edid_type edid)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id;
+	struct eld_entry eld;
+	struct eld_sad *sad;
+
+	igt_require(eld_is_supported());
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because audio cannot be played on inactive
+	 * connectors. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	igt_assert(eld_get_igt(&eld));
+	igt_assert(eld.sads_len == 1);
+
+	sad = &eld.sads[0];
+	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
+	igt_assert(sad->channels == 2);
+	igt_assert(sad->rates ==
+		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
+		    CEA_SAD_SAMPLING_RATE_48KHZ));
+	igt_assert(sad->bits ==
+		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
+		    CEA_SAD_SAMPLE_SIZE_24));
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+}
+
+IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("dp-audio", DisplayPort) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("dp-audio-edid", DisplayPort)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_DP_AUDIO);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("hdmi-audio-edid", HDMIA)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_HDMI_AUDIO);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
similarity index 100%
rename from tests/chamelium/kms_color_chamelium.c
rename to tests/chamelium/kms_chamelium_color.c
diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
new file mode 100644
index 00000000..6c069112
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_edid.c
@@ -0,0 +1,532 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the EDID functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_chamelium.h"
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+#include "monitor_edids/dp_edids.h"
+#include "monitor_edids/hdmi_edids.h"
+#include "monitor_edids/monitor_edids_helper.h"
+
+#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
+
+static void get_connectors_link_status_failed(chamelium_data_t *data,
+					      bool *link_status_failed)
+{
+	drmModeConnector *connector;
+	uint64_t link_status;
+	drmModePropertyPtr prop;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		connector = chamelium_port_get_connector(data->chamelium,
+							 data->ports[p], false);
+
+		igt_assert(kmstest_get_property(
+			data->drm_fd, connector->connector_id,
+			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
+			&link_status, &prop));
+
+		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
+
+		drmModeFreeProperty(prop);
+		drmModeFreeConnector(connector);
+	}
+}
+
+static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
+		       drmModeModeInfo *mode)
+{
+	struct chamelium_video_params video_params = { 0 };
+	double mode_clock;
+	int mode_hsync_offset, mode_vsync_offset;
+	int mode_hsync_width, mode_vsync_width;
+	int mode_hsync_polarity, mode_vsync_polarity;
+
+	chamelium_port_get_video_params(chamelium, port, &video_params);
+
+	mode_clock = (double)mode->clock / 1000;
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
+		/* this is what chamelium understands as offsets for DP */
+		mode_hsync_offset = mode->htotal - mode->hsync_start;
+		mode_vsync_offset = mode->vtotal - mode->vsync_start;
+	} else {
+		/* and this is what they are for other connectors */
+		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
+		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
+	}
+
+	mode_hsync_width = mode->hsync_end - mode->hsync_start;
+	mode_vsync_width = mode->vsync_end - mode->vsync_start;
+
+	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	igt_debug("Checking video mode:\n");
+	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
+		  mode_clock, MODE_CLOCK_ACCURACY * 100);
+	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
+		  mode->hdisplay);
+	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
+		  mode->vdisplay);
+	igt_debug("hsync_offset: got %d, expected %d\n",
+		  video_params.hsync_offset, mode_hsync_offset);
+	igt_debug("vsync_offset: got %d, expected %d\n",
+		  video_params.vsync_offset, mode_vsync_offset);
+	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
+		  mode->htotal);
+	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
+		  mode->vtotal);
+	igt_debug("hsync_width: got %d, expected %d\n",
+		  video_params.hsync_width, mode_hsync_width);
+	igt_debug("vsync_width: got %d, expected %d\n",
+		  video_params.vsync_width, mode_vsync_width);
+	igt_debug("hsync_polarity: got %d, expected %d\n",
+		  video_params.hsync_polarity, mode_hsync_polarity);
+	igt_debug("vsync_polarity: got %d, expected %d\n",
+		  video_params.vsync_polarity, mode_vsync_polarity);
+
+	if (!isnan(video_params.clock)) {
+		igt_assert(video_params.clock >
+			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
+		igt_assert(video_params.clock <
+			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
+	}
+	igt_assert(video_params.hactive == mode->hdisplay);
+	igt_assert(video_params.vactive == mode->vdisplay);
+	igt_assert(video_params.hsync_offset == mode_hsync_offset);
+	igt_assert(video_params.vsync_offset == mode_vsync_offset);
+	igt_assert(video_params.htotal == mode->htotal);
+	igt_assert(video_params.vtotal == mode->vtotal);
+	igt_assert(video_params.hsync_width == mode_hsync_width);
+	igt_assert(video_params.vsync_width == mode_vsync_width);
+	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
+	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
+}
+
+static const char igt_custom_edid_type_read_desc[] =
+	"Make sure the EDID exposed by KMS is the same as the screen's";
+static void igt_custom_edid_type_read(chamelium_data_t *data,
+				      struct chamelium_port *port,
+				      enum igt_custom_edid_type edid)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector;
+	size_t raw_edid_size;
+	const struct edid *raw_edid;
+	uint64_t edid_blob_id;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_skip_on(chamelium_check_analog_bridge(data, port));
+
+	connector = chamelium_port_get_connector(data->chamelium, port, true);
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob_id != 0);
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
+	raw_edid_size = edid_get_size(raw_edid);
+	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+}
+
+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(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   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;
+
+		monitor_edid *edid = &edids_list[i];
+		igt_info("Testing out the EDID for %s\n",
+			 monitor_edid_get_name(edid));
+
+		/* Getting and Setting the EDID on Chamelium. */
+		chamelium_edid =
+			get_chameleon_edid_from_monitor_edid(chamelium, 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);
+		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
+		chamelium_create_fb_for_mode(data, &fb, &mode);
+		output = chamelium_get_output_for_port(data, port);
+		pipe = chamelium_get_pipe_for_output(&data->display, output);
+		igt_output_set_pipe(output, pipe);
+		chamelium_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);
+}
+
+static const char igt_edid_resolution_list_desc[] =
+	"Get an EDID with many modes of different configurations, set them on the screen and check the"
+	" screen resolution matches the mode resolution.";
+
+static void edid_resolution_list(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct chamelium *chamelium = data->chamelium;
+	struct udev_monitor *mon = igt_watch_uevents();
+	drmModeConnector *connector;
+	drmModeModeInfoPtr modes;
+	int count_modes;
+	int i;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	chamelium_unplug(chamelium, port);
+	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
+
+	igt_flush_uevents(mon);
+	chamelium_plug(chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_CONNECTED);
+	igt_flush_uevents(mon);
+
+	connector = chamelium_port_get_connector(chamelium, port, true);
+	modes = connector->modes;
+	count_modes = connector->count_modes;
+
+	output = chamelium_get_output_for_port(data, port);
+	pipe = chamelium_get_pipe_for_output(&data->display, output);
+	igt_output_set_pipe(output, pipe);
+
+	for (i = 0; i < count_modes; ++i)
+		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
+
+	for (i = 0; i < count_modes; ++i) {
+		struct igt_fb fb = { 0 };
+		bool is_video_stable;
+		int screen_res_w, screen_res_h;
+
+		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
+			 modes[i].vrefresh);
+
+		/* Set the screen mode with the one we chose. */
+		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
+		chamelium_enable_output(data, port, output, &modes[i], &fb);
+		is_video_stable = chamelium_port_wait_video_input_stable(
+			chamelium, port, 10);
+		igt_assert(is_video_stable);
+
+		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
+					      &screen_res_h);
+		igt_assert_eq(screen_res_w, modes[i].hdisplay);
+		igt_assert_eq(screen_res_h, modes[i].vdisplay);
+
+		igt_remove_fb(data->drm_fd, &fb);
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_suspend_resume_edid_change_desc[] =
+	"Simulate a screen being unplugged and another screen being plugged "
+	"during suspend, check that a uevent is sent and connector status is "
+	"updated";
+static void test_suspend_resume_edid_change(chamelium_data_t *data,
+					    struct chamelium_port *port,
+					    enum igt_suspend_state state,
+					    enum igt_suspend_test test,
+					    enum igt_custom_edid_type edid,
+					    enum igt_custom_edid_type alt_edid)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	bool link_status_failed[2][data->port_count];
+	int p;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Catch the event and flush all remaining ones. */
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_flush_uevents(mon);
+
+	/* First plug in the port */
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	/*
+	 * Change the edid before we suspend. On resume, the machine should
+	 * notice the EDID change and fire a hotplug event.
+	 */
+	chamelium_set_edid(data, port, alt_edid);
+
+	get_connectors_link_status_failed(data, link_status_failed[0]);
+
+	igt_flush_uevents(mon);
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	get_connectors_link_status_failed(data, link_status_failed[1]);
+
+	for (p = 0; p < data->port_count; p++)
+		igt_skip_on(!link_status_failed[0][p] &&
+			    link_status_failed[1][p]);
+}
+
+static const char test_mode_timings_desc[] =
+	"For each mode of the IGT base EDID, perform a modeset and check the "
+	"mode detected by the Chamelium receiver matches the mode we set";
+static void test_mode_timings(chamelium_data_t *data,
+			      struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	igt_require(chamelium_supports_get_video_params(data->chamelium));
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+		int fb_id;
+		struct igt_fb fb;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		/* Trigger the FSM */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
+
+		check_mode(data->chamelium, port, mode);
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("dp-edid-read", DisplayPort)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_4K,
+					       ARRAY_SIZE(DP_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-non-4k",
+				  DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
+					       ARRAY_SIZE(DP_EDIDS_NON_4K));
+
+		igt_describe(igt_edid_resolution_list_desc);
+		connector_subtest("dp-edid-resolution-list", DisplayPort)
+			edid_resolution_list(&data, port);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-hibernate",
+				  DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("dp-mode-timings", DisplayPort)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("hdmi-edid-read", HDMIA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("hdmi-mode-timings", HDMIA)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("vga-edid-read", VGA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
new file mode 100644
index 00000000..008bc34b
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_frames.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Lyude Paul <lyude@redhat.com>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+#define connector_dynamic_subtest(name__, type__)                   \
+	igt_subtest_with_dynamic(name__)                            \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+struct vic_mode {
+	int hactive, vactive;
+	int vrefresh; /* Hz */
+	uint32_t picture_ar;
+};
+
+static int chamelium_vga_modes[][2] = {
+	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
+	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
+	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
+	{ 640, 480 },	{ -1, -1 },
+};
+
+/* Maps Video Identification Codes to a mode */
+static const struct vic_mode vic_modes[] = {
+	[16] = {
+		.hactive = 1920,
+		.vactive = 1080,
+		.vrefresh = 60,
+		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
+	},
+};
+
+/* Maps aspect ratios to their mode flag */
+static const uint32_t mode_ar_flags[] = {
+	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
+};
+
+static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
+{
+	int i = 0;
+
+	while (chamelium_vga_modes[i][0] != -1) {
+		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
+		    mode->vdisplay == chamelium_vga_modes[i][1])
+			return false;
+
+		i++;
+	}
+
+	return true;
+}
+
+static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
+			    igt_output_t *output, drmModeModeInfo *mode,
+			    uint32_t fourcc, enum chamelium_check check,
+			    int count)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+	struct igt_fb frame_fb, fb;
+	int i, fb_id, captured_frame_count;
+	int frame_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &fb);
+	igt_assert(fb_id > 0);
+
+	frame_id =
+		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
+	igt_assert(frame_id > 0);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
+
+	chamelium_enable_output(data, port, output, mode, &frame_fb);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		igt_crc_t *expected_crc;
+		igt_crc_t *crc;
+
+		/* We want to keep the display running for a little bit, since
+		 * there's always the potential the driver isn't able to keep
+		 * the display running properly for very long
+		 */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == count);
+
+		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		for (i = 0; i < captured_frame_count; i++)
+			chamelium_assert_crc_eq_or_dump(
+				data->chamelium, expected_crc, &crc[i], &fb, i);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_ANALOG ||
+		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		igt_assert(count == 1);
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+
+		if (check == CHAMELIUM_CHECK_ANALOG)
+			chamelium_crop_analog_frame(dump, mode->hdisplay,
+						    mode->vdisplay);
+
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	igt_remove_fb(data->drm_fd, &frame_fb);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static enum infoframe_avi_picture_aspect_ratio
+get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
+{
+	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
+	switch (aspect_ratio) {
+	case DRM_MODE_PICTURE_ASPECT_4_3:
+		return INFOFRAME_AVI_PIC_AR_4_3;
+	case DRM_MODE_PICTURE_ASPECT_16_9:
+		return INFOFRAME_AVI_PIC_AR_16_9;
+	default:
+		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
+	}
+}
+
+static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
+				 drmModeModeInfo *drm_mode)
+{
+	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
+
+	return vic_mode->hactive == drm_mode->hdisplay &&
+	       vic_mode->vactive == drm_mode->vdisplay &&
+	       vic_mode->vrefresh == drm_mode->vrefresh &&
+	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
+}
+
+static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
+				   uint32_t height, uint32_t format,
+				   uint64_t modifier, size_t *stride)
+{
+	size_t stride_min;
+	uint32_t max_tile_w = 4, tile_w, tile_h;
+	int i;
+	struct igt_fb dummy;
+
+	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
+
+	/* Randomize the stride to less than twice the minimum. */
+	*stride = (rand() % stride_min) + stride_min;
+
+	/*
+	 * Create a dummy FB to determine bpp for each plane, and calculate
+	 * the maximum tile width from that.
+	 */
+	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
+	for (i = 0; i < dummy.num_planes; i++) {
+		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
+				     &tile_w, &tile_h);
+
+		if (tile_w > max_tile_w)
+			max_tile_w = tile_w;
+	}
+	igt_remove_fb(data->drm_fd, &dummy);
+
+	/*
+	 * Pixman requires the stride to be aligned to 32-bits, which is
+	 * reflected in the initial value of max_tile_w and the hw
+	 * may require a multiple of tile width, choose biggest of the 2.
+	 */
+	*stride = ALIGN(*stride, max_tile_w);
+}
+
+static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
+				  uint32_t height, uint32_t format,
+				  uint64_t *modifier)
+{
+	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
+		/* Randomize the column height to less than twice the minimum.
+		 */
+		size_t column_height = (rand() % height) + height;
+
+		igt_debug(
+			"Selecting VC4 SAND256 tiling with column height %ld\n",
+			column_height);
+
+		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
+			column_height);
+	}
+}
+
+static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
+				  drmModeModeInfo *mode, uint32_t *width,
+				  uint32_t *height, uint32_t *format,
+				  uint64_t *modifier, bool allow_yuv)
+{
+	int min_dim;
+	uint32_t idx[plane->format_mod_count];
+	unsigned int count = 0;
+	unsigned int i;
+
+	/* First pass to count the supported formats. */
+	for (i = 0; i < plane->format_mod_count; i++)
+		if (igt_fb_supported_format(plane->formats[i]) &&
+		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
+			idx[count++] = i;
+
+	igt_assert(count > 0);
+
+	i = idx[rand() % count];
+	*format = plane->formats[i];
+	*modifier = plane->modifiers[i];
+
+	update_tiled_modifier(plane, *width, *height, *format, modifier);
+
+	/*
+	 * Randomize width and height in the mode dimensions range.
+	 *
+	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
+	 * least min_dim, because src_w = width - (rand % w / 2).
+	 *
+	 * Use a minimum dimension of 16 for YUV, because planar YUV
+	 * subsamples the UV plane.
+	 */
+	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
+
+	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
+	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
+}
+
+static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
+			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
+			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
+			    struct igt_fb *fb)
+{
+	igt_plane_set_fb(plane, fb);
+
+	igt_plane_set_position(plane, crtc_x, crtc_y);
+	igt_plane_set_size(plane, crtc_w, crtc_h);
+
+	igt_fb_set_position(fb, plane, src_x, src_y);
+	igt_fb_set_size(fb, plane, src_w, src_h);
+}
+
+static void randomize_plane_coordinates(
+	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
+	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
+	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
+	int32_t *crtc_y, bool allow_scaling)
+{
+	bool is_yuv = igt_format_is_yuv(fb->drm_format);
+	uint32_t width = fb->width, height = fb->height;
+	double ratio;
+	int ret;
+
+	/* Randomize source offset in the first half of the original size. */
+	*src_x = rand() % (width / 2);
+	*src_y = rand() % (height / 2);
+
+	/* The source size only includes the active source area. */
+	*src_w = width - *src_x;
+	*src_h = height - *src_y;
+
+	if (allow_scaling) {
+		*crtc_w = (rand() % mode->hdisplay) + 1;
+		*crtc_h = (rand() % mode->vdisplay) + 1;
+
+		/*
+		 * Don't bother with scaling if dimensions are quite close in
+		 * order to get non-scaling cases more frequently. Also limit
+		 * scaling to 3x to avoid aggressive filtering that makes
+		 * comparison less reliable, and don't go above 2x downsampling
+		 * to avoid possible hw limitations.
+		 */
+
+		ratio = ((double)*crtc_w / *src_w);
+		if (ratio < 0.5)
+			*src_w = *crtc_w * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_w = *src_w;
+		else if (ratio > 3.0)
+			*crtc_w = *src_w * 3;
+
+		ratio = ((double)*crtc_h / *src_h);
+		if (ratio < 0.5)
+			*src_h = *crtc_h * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_h = *src_h;
+		else if (ratio > 3.0)
+			*crtc_h = *src_h * 3;
+	} else {
+		*crtc_w = *src_w;
+		*crtc_h = *src_h;
+	}
+
+	if (*crtc_w != *src_w || *crtc_h != *src_h) {
+		/*
+		 * When scaling is involved, make sure to not go off-bounds or
+		 * scaled clipping may result in decimal dimensions, that most
+		 * drivers don't support.
+		 */
+		if (*crtc_w < mode->hdisplay)
+			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
+		else
+			*crtc_x = 0;
+
+		if (*crtc_h < mode->vdisplay)
+			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
+		else
+			*crtc_y = 0;
+	} else {
+		/*
+		 * Randomize the on-crtc position and allow the plane to go
+		 * off-display by less than half of its on-crtc dimensions.
+		 */
+		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
+		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
+	}
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	ret = igt_display_try_commit_atomic(
+		&data->display,
+		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
+		NULL);
+	if (!ret)
+		return;
+
+	/* Coordinates are logged in the dumped debug log, so only report w/h on
+	 * failure here. */
+	igt_assert_f(ret != -ENOSPC,
+		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
+		     width, height);
+
+	/* Make YUV coordinates a multiple of 2 and retry the math. */
+	if (is_yuv) {
+		*src_x &= ~1;
+		*src_y &= ~1;
+		*src_w &= ~1;
+		*src_h &= ~1;
+		/* To handle 1:1 scaling, clear crtc_w/h too. */
+		*crtc_w &= ~1;
+		*crtc_h &= ~1;
+
+		if (*crtc_x < 0 && (*crtc_x & 1))
+			(*crtc_x)++;
+		else
+			*crtc_x &= ~1;
+
+		/* If negative, round up to 0 instead of down */
+		if (*crtc_y < 0 && (*crtc_y & 1))
+			(*crtc_y)++;
+		else
+			*crtc_y &= ~1;
+
+		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
+				*crtc_h, *crtc_x, *crtc_y, fb);
+		ret = igt_display_try_commit_atomic(
+			&data->display,
+			DRM_MODE_ATOMIC_TEST_ONLY |
+				DRM_MODE_ATOMIC_ALLOW_MODESET,
+			NULL);
+		if (!ret)
+			return;
+	}
+
+	igt_assert(!ret || allow_scaling);
+	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
+		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
+
+	*crtc_w = *src_w;
+	*crtc_h = *src_h;
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	igt_display_commit_atomic(&data->display,
+				  DRM_MODE_ATOMIC_TEST_ONLY |
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+				  NULL);
+}
+
+static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
+			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
+			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
+			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
+{
+	cairo_surface_t *surface;
+	cairo_surface_t *clipped_surface;
+	cairo_t *cr;
+
+	surface = igt_get_cairo_surface(data->drm_fd, fb);
+
+	if (src_x || src_y) {
+		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+							     src_w, src_h);
+
+		cr = cairo_create(clipped_surface);
+
+		cairo_translate(cr, -1. * src_x, -1. * src_y);
+
+		cairo_set_source_surface(cr, surface, 0, 0);
+
+		cairo_paint(cr);
+		cairo_surface_flush(clipped_surface);
+
+		cairo_destroy(cr);
+	} else {
+		clipped_surface = surface;
+	}
+
+	cr = cairo_create(result);
+
+	cairo_translate(cr, crtc_x, crtc_y);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
+	}
+
+	cairo_set_source_surface(cr, clipped_surface, 0, 0);
+	cairo_surface_destroy(clipped_surface);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_pattern_set_filter(cairo_get_source(cr),
+					 CAIRO_FILTER_BILINEAR);
+		cairo_pattern_set_extend(cairo_get_source(cr),
+					 CAIRO_EXTEND_NONE);
+	}
+
+	cairo_paint(cr);
+	cairo_surface_flush(result);
+
+	cairo_destroy(cr);
+}
+
+static void prepare_randomized_plane(chamelium_data_t *data,
+				     drmModeModeInfo *mode, igt_plane_t *plane,
+				     struct igt_fb *overlay_fb,
+				     unsigned int index,
+				     cairo_surface_t *result_surface,
+				     bool allow_scaling, bool allow_yuv)
+{
+	struct igt_fb pattern_fb;
+	uint32_t overlay_fb_w, overlay_fb_h;
+	uint32_t overlay_src_w, overlay_src_h;
+	uint32_t overlay_src_x, overlay_src_y;
+	int32_t overlay_crtc_x, overlay_crtc_y;
+	uint32_t overlay_crtc_w, overlay_crtc_h;
+	uint32_t format;
+	uint64_t modifier;
+	size_t stride;
+	bool tiled;
+	int fb_id;
+
+	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
+			      &format, &modifier, allow_yuv);
+
+	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
+	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
+		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
+		  tiled ? "tiled" : "linear");
+
+	/* Get a pattern framebuffer for the overlay plane. */
+	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
+					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
+			       modifier, &stride);
+
+	igt_debug("Plane %d: stride %ld\n", index, stride);
+
+	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
+					   modifier, stride);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_coordinates(data, plane, mode, overlay_fb,
+				    &overlay_src_w, &overlay_src_h,
+				    &overlay_src_x, &overlay_src_y,
+				    &overlay_crtc_w, &overlay_crtc_h,
+				    &overlay_crtc_x, &overlay_crtc_y,
+				    allow_scaling);
+
+	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
+		  overlay_src_h);
+	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
+		  overlay_src_x, overlay_src_y);
+	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
+		  overlay_crtc_h);
+	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
+		  overlay_crtc_y);
+
+	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
+			 overlay_src_x, overlay_src_y, overlay_crtc_w,
+			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
+			 &pattern_fb);
+
+	/* Remove the original pattern framebuffer. */
+	igt_remove_fb(data->drm_fd, &pattern_fb);
+}
+
+static const char test_display_one_mode_desc[] =
+	"Pick the first mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_one_mode(chamelium_data_t *data,
+				  struct chamelium_port *port, uint32_t fourcc,
+				  enum chamelium_check check, int count)
+{
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	igt_output_t *output;
+	igt_plane_t *primary;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	igt_require(igt_plane_has_format_mod(primary, fourcc,
+					     DRM_FORMAT_MOD_LINEAR));
+
+	mode = &connector->modes[0];
+	if (check == CHAMELIUM_CHECK_ANALOG) {
+		bool bridge = chamelium_check_analog_bridge(data, port);
+
+		igt_assert(!(bridge && prune_vga_mode(data, mode)));
+	}
+
+	do_test_display(data, port, output, mode, fourcc, check, count);
+
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_all_modes_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_all_modes(chamelium_data_t *data,
+				   struct chamelium_port *port, uint32_t fourcc,
+				   enum chamelium_check check, int count)
+{
+	bool bridge;
+	int i, count_modes;
+
+	if (check == CHAMELIUM_CHECK_ANALOG)
+		bridge = chamelium_check_analog_bridge(data, port);
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+		igt_require(igt_plane_has_format_mod(primary, fourcc,
+						     DRM_FORMAT_MOD_LINEAR));
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
+		    prune_vga_mode(data, mode))
+			continue;
+
+		do_test_display(data, port, output, mode, fourcc, check, count);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_frame_dump_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then download the captured frames and compare them "
+	"bit-by-bit to the sent ones";
+static void test_display_frame_dump(chamelium_data_t *data,
+				    struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		struct igt_fb fb;
+		struct chamelium_frame_dump *frame;
+		drmModeModeInfo *mode;
+		drmModeConnector *connector;
+		int fb_id, j;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		igt_debug("Reading frame dumps from Chamelium...\n");
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
+		for (j = 0; j < 5; j++) {
+			frame = chamelium_read_captured_frame(data->chamelium,
+							      j);
+			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
+			chamelium_destroy_frame_dump(frame);
+		}
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_aspect_ratio_desc[] =
+	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
+	"check they include the relevant fields";
+static void test_display_aspect_ratio(chamelium_data_t *data,
+				      struct chamelium_port *port)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	int fb_id, i;
+	struct igt_fb fb;
+	bool found, ok;
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_avi infoframe_avi;
+	uint8_t vic = 16; /* TODO: test more VICs */
+	const struct vic_mode *vic_mode;
+	uint32_t aspect_ratio;
+	enum infoframe_avi_picture_aspect_ratio frame_ar;
+
+	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port,
+					  IGT_CUSTOM_EDID_ASPECT_RATIO);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	vic_mode = &vic_modes[vic];
+	aspect_ratio = vic_mode->picture_ar;
+
+	found = false;
+	igt_assert(connector->count_modes > 0);
+	for (i = 0; i < connector->count_modes; i++) {
+		mode = &connector->modes[i];
+
+		if (vic_mode_matches_drm(vic_mode, mode)) {
+			found = true;
+			break;
+		}
+	}
+	igt_assert_f(found,
+		     "Failed to find mode with the correct aspect ratio\n");
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
+						 CHAMELIUM_INFOFRAME_AVI);
+	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
+
+	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
+				 infoframe->payload, infoframe->payload_size);
+	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
+
+	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
+
+	igt_debug("Checking AVI InfoFrame\n");
+	igt_debug("Picture aspect ratio: got %d, expected %d\n",
+		  infoframe_avi.picture_aspect_ratio, frame_ar);
+	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
+		  infoframe_avi.vic, vic);
+
+	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
+	igt_assert(infoframe_avi.vic == vic);
+
+	chamelium_infoframe_destroy(infoframe);
+	igt_remove_fb(data->drm_fd, &fb);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_planes_random_desc[] =
+	"Setup a few overlay planes with random parameters, capture the frame "
+	"and check it matches the expected output";
+static void test_display_planes_random(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum chamelium_check check)
+{
+	igt_output_t *output;
+	drmModeModeInfo *mode;
+	igt_plane_t *primary_plane;
+	struct igt_fb primary_fb;
+	struct igt_fb result_fb;
+	struct igt_fb *overlay_fbs;
+	igt_crc_t *crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
+	unsigned int overlay_planes_max = 0;
+	unsigned int overlay_planes_count;
+	cairo_surface_t *result_surface;
+	int captured_frame_count;
+	bool allow_scaling;
+	bool allow_yuv;
+	unsigned int i;
+	unsigned int fb_id;
+
+	switch (check) {
+	case CHAMELIUM_CHECK_CRC:
+		allow_scaling = false;
+		allow_yuv = false;
+		break;
+	case CHAMELIUM_CHECK_CHECKERBOARD:
+		allow_scaling = true;
+		allow_yuv = true;
+		break;
+	default:
+		igt_assert(false);
+	}
+
+	srand(time(NULL));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Find the connector and pipe. */
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+
+	mode = igt_output_get_mode(output);
+
+	/* Get a framebuffer for the primary plane. */
+	primary_plane =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary_plane);
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
+	igt_assert(fb_id > 0);
+
+	/* Get a framebuffer for the cairo composition result. */
+	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
+			      &result_fb);
+	igt_assert(fb_id > 0);
+
+	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
+
+	/* Paint the primary framebuffer on the result surface. */
+	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
+			 &primary_fb);
+
+	/* Configure the primary plane. */
+	igt_plane_set_fb(primary_plane, &primary_fb);
+
+	overlay_planes_max =
+		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
+
+	/* Limit the number of planes to a reasonable scene. */
+	overlay_planes_max = min(overlay_planes_max, 4u);
+
+	overlay_planes_count = (rand() % overlay_planes_max) + 1;
+	igt_debug("Using %d overlay planes\n", overlay_planes_count);
+
+	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
+
+	for (i = 0; i < overlay_planes_count; i++) {
+		struct igt_fb *overlay_fb = &overlay_fbs[i];
+		igt_plane_t *plane = igt_output_get_plane_type_index(
+			output, DRM_PLANE_TYPE_OVERLAY, i);
+		igt_assert(plane);
+
+		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
+					 result_surface, allow_scaling,
+					 allow_yuv);
+	}
+
+	cairo_surface_destroy(result_surface);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&result_fb);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == 1);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &result_fb, 0);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &result_fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	for (i = 0; i < overlay_planes_count; i++)
+		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
+
+	free(overlay_fbs);
+
+	igt_remove_fb(data->drm_fd, &primary_fb);
+	igt_remove_fb(data->drm_fd, &result_fb);
+}
+
+IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-single", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("dp-crc-fast", DisplayPort)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-multiple", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("dp-frame-dump", DisplayPort)
+			test_display_frame_dump(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-single", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("hdmi-crc-fast", HDMIA)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-multiple", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CRC, 1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-crc-planes-random", HDMIA)
+			test_display_planes_random(&data, port,
+						   CHAMELIUM_CHECK_CRC);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (!igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CHECKERBOARD,
+						1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-cmp-planes-random", HDMIA)
+			test_display_planes_random(
+				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("hdmi-frame-dump", HDMIA)
+			test_display_frame_dump(&data, port);
+
+		igt_describe(test_display_aspect_ratio_desc);
+		connector_subtest("hdmi-aspect-ratio", HDMIA)
+			test_display_aspect_ratio(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("vga-frame-dump", VGA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_ANALOG, 1);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
new file mode 100644
index 00000000..b9544288
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+
+void chamelium_init_test(chamelium_data_t *data)
+{
+	int i;
+
+	/* So fbcon doesn't try to reprobe things itself */
+	kmstest_set_vt_graphics_mode();
+
+	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
+	igt_display_require(&data->display, data->drm_fd);
+	igt_require(data->display.is_atomic);
+
+	/*
+	 * XXX: disabling modeset, can be removed when
+	 * igt_display_require will start doing this for us
+	 */
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	/* we need to initalize chamelium after igt_display_require */
+	data->chamelium = chamelium_init(data->drm_fd, &data->display);
+	igt_require(data->chamelium);
+
+	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
+
+	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
+		data->edids[i] = chamelium_new_edid(data->chamelium,
+						    igt_kms_get_custom_edid(i));
+	}
+}
+
+/* Wait for hotplug and return the remaining time left from timeout */
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
+{
+	struct timespec start, end;
+	int elapsed;
+	bool detected;
+
+	igt_assert_eq(igt_gettime(&start), 0);
+	detected = igt_hotplug_detected(mon, *timeout);
+	igt_assert_eq(igt_gettime(&end), 0);
+
+	elapsed = igt_time_elapsed(&start, &end);
+	igt_assert_lte(0, elapsed);
+	*timeout = max(0, *timeout - elapsed);
+
+	return detected;
+}
+
+/**
+ * chamelium_wait_for_connector_after_hotplug:
+ *
+ * Waits for the connector attached to @port to have a status of @status after
+ * it's plugged/unplugged.
+ *
+ */
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status)
+{
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int hotplug_count = 0;
+
+	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
+		  chamelium_port_get_name(port),
+		  kmstest_connector_status_str(status));
+
+	while (timeout > 0) {
+		if (!chamelium_wait_for_hotplug(mon, &timeout))
+			break;
+
+		hotplug_count++;
+
+		if (chamelium_reprobe_connector(&data->display, data->chamelium,
+						port) == status)
+			return;
+	}
+
+	igt_assert_f(
+		false,
+		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
+		chamelium_port_get_name(port),
+		kmstest_connector_status_str(status),
+		kmstest_connector_status_str(chamelium_reprobe_connector(
+			&data->display, data->chamelium, port)),
+		hotplug_count);
+}
+
+/**
+ * chamelium_port_get_connector:
+ * @data: The Chamelium data instance to use
+ * @port: The chamelium port to prepare its connector
+ * @edid: The chamelium's default EDID has a lot of resolutions, way more then
+ * 		  we need to test. Additionally the default EDID doesn't support
+ *        HDMI audio.
+ *
+ * Makes sure the output display of the connector attached to @port is connected
+ * and ready for use.
+ *
+ * Returns: a pointer to the enabled igt_output_t
+ */
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	/* The chamelium's default EDID has a lot of resolutions, way more then
+	 * we need to test. Additionally the default EDID doesn't support HDMI
+	 * audio.
+	 */
+	chamelium_set_edid(data, port, edid);
+
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_display_reset(display);
+
+	output = chamelium_get_output_for_port(data, port);
+
+	/* Refresh pipe to update connected status */
+	igt_output_set_pipe(output, PIPE_NONE);
+
+	pipe = chamelium_get_pipe_for_output(display, output);
+	igt_output_set_pipe(output, pipe);
+
+	return output;
+}
+
+/**
+ * chamelium_enable_output:
+ *
+ * Modesets the connector attached to @port for the assigned @mode and draws the
+ * @fb.
+ *
+ */
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb)
+{
+	igt_display_t *display = output->display;
+	igt_plane_t *primary =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+
+	igt_assert(primary);
+
+	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
+	igt_plane_set_fb(primary, fb);
+	igt_output_override_mode(output, mode);
+
+	/* Clear any color correction values that might be enabled */
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_GAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
+		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
+					       NULL, 0);
+
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
+		usleep(250000);
+
+	drmModeFreeConnector(connector);
+}
+
+/* Return pipe attached to @outpu.t */
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output)
+{
+	enum pipe pipe;
+
+	for_each_pipe(display, pipe) {
+		if (igt_pipe_connector_valid(pipe, output)) {
+			return pipe;
+		}
+	}
+
+	igt_assert_f(false, "No pipe found for output %s\n",
+		     igt_output_name(output));
+}
+
+static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
+					 size_t height, size_t stride,
+					 size_t block_size)
+{
+	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
+			      0xffffffff };
+	unsigned i, j;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			*(data + i * stride / 4 +
+			  j) = colors[((j / block_size) + (i / block_size)) % 5];
+}
+
+/**
+ * chamelium_get_pattern_fb:
+ *
+ * Creates an @fb with an xr24 pattern and returns the fb_id.
+ *
+ */
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb)
+{
+	int fb_id;
+	void *ptr;
+
+	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
+
+	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
+			      DRM_FORMAT_MOD_LINEAR, fb);
+	igt_assert(fb_id > 0);
+
+	ptr = igt_fb_map_buffer(fb->fd, fb);
+	igt_assert(ptr);
+
+	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
+				     block_size);
+	igt_fb_unmap_buffer(fb, ptr);
+
+	return fb_id;
+}
+
+/* Generate a simple @fb for the size of @mode. */
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode)
+{
+	int fb_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, fb);
+
+	igt_assert(fb_id > 0);
+}
+
+/* Returns the first preferred mode for the connector attached to @port. */
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(chamelium, port, false);
+	drmModeModeInfo mode;
+	igt_assert(&connector->modes[0] != NULL);
+	memcpy(&mode, &connector->modes[0], sizeof(mode));
+	drmModeFreeConnector(connector);
+	return mode;
+}
+
+/* Returns the igt display output for the connector attached to @port. */
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, true);
+	igt_output_t *output =
+		igt_output_from_connector(&data->display, connector);
+	drmModeFreeConnector(connector);
+	igt_assert(output != NULL);
+	return output;
+}
+
+/* Set the EDID of index @edid to Chamelium's @port. */
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid)
+{
+	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
+}
+
+/**
+ * chamelium_check_analog_bridge:
+ *
+ * Check if the connector associalted to @port is an analog bridge by checking
+ * if it has its own EDID.
+ *
+ */
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+	uint64_t edid_blob_id;
+	const struct edid *edid;
+	char edid_vendor[3];
+
+	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
+		drmModeFreeConnector(connector);
+		return false;
+	}
+
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	edid = (const struct edid *)edid_blob->data;
+	edid_get_mfg(edid, edid_vendor);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+
+	/* Analog bridges provide their own EDID */
+	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
+	    edid_vendor[2] != 'T')
+		return true;
+
+	return false;
+}
\ No newline at end of file
diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
new file mode 100644
index 00000000..09fa4829
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+
+#include "igt.h"
+
+#define ONLINE_TIMEOUT 20 /* seconds */
+
+#define for_each_port(p, port)                                 \
+	for (p = 0, port = data.ports[p]; p < data.port_count; \
+	     p++, port = data.ports[p])
+
+#define connector_subtest(name__, type__)                           \
+	igt_subtest(name__)                                         \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+/*
+ * The chamelium data structure is used to store all the information known about
+ * chamelium to run the tests.
+ */
+typedef struct {
+	struct chamelium *chamelium;
+	struct chamelium_port **ports;
+	igt_display_t display;
+	int port_count;
+
+	int drm_fd;
+
+	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
+} chamelium_data_t;
+
+void chamelium_init_test(chamelium_data_t *data);
+
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status);
+
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid);
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb);
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output);
+
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb);
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode);
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port);
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port);
+
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid);
+
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port);
+
+#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
new file mode 100644
index 00000000..8a4e1aba
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_hpd.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the HPD functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "kms_chamelium_helper.h"
+
+#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
+#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
+
+#define HPD_TOGGLE_COUNT_VGA 5
+#define HPD_TOGGLE_COUNT_DP_HDMI 15
+#define HPD_TOGGLE_COUNT_FAST 3
+
+enum test_modeset_mode {
+	TEST_MODESET_ON,
+	TEST_MODESET_ON_OFF,
+	TEST_MODESET_OFF,
+};
+
+static void try_suspend_resume_hpd(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   enum igt_suspend_state state,
+				   enum igt_suspend_test test,
+				   struct udev_monitor *mon, bool connected)
+{
+	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
+						     DRM_MODE_CONNECTED;
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int delay;
+	int p;
+
+	igt_flush_uevents(mon);
+
+	delay = igt_get_autoresume_delay(state) * 1000 / 2;
+
+	if (port) {
+		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
+					      !connected);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			port = data->ports[p];
+			chamelium_schedule_hpd_toggle(data->chamelium, port,
+						      delay, !connected);
+		}
+
+		port = NULL;
+	}
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	if (port) {
+		igt_assert_eq(chamelium_reprobe_connector(
+				      &data->display, data->chamelium, port),
+			      target_state);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			drmModeConnection current_state;
+
+			port = data->ports[p];
+			/*
+			 * There could be as many hotplug events sent by
+			 * driver as connectors we scheduled an HPD toggle on
+			 * above, depending on timing. So if we're not seeing
+			 * the expected connector state try to wait for an HPD
+			 * event for each connector/port.
+			 */
+			current_state = chamelium_reprobe_connector(
+				&data->display, data->chamelium, port);
+			if (p > 0 && current_state != target_state) {
+				igt_assert(chamelium_wait_for_hotplug(
+					mon, &timeout));
+				current_state = chamelium_reprobe_connector(
+					&data->display, data->chamelium, port);
+			}
+
+			igt_assert_eq(current_state, target_state);
+		}
+
+		port = NULL;
+	}
+}
+
+static const char test_basic_hotplug_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug";
+static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
+			 int toggle_count, enum test_modeset_mode modeset_mode)
+{
+	int i;
+	enum pipe pipe;
+	struct igt_fb fb = { 0 };
+	drmModeModeInfo mode;
+	struct udev_monitor *mon = igt_watch_uevents();
+	igt_output_t *output = chamelium_get_output_for_port(data, port);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+
+	for (i = 0; i < toggle_count; i++) {
+		igt_flush_uevents(mon);
+
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF ||
+		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
+			if (i == 0) {
+				/* We can only get mode and pipe once we are
+				 * connected */
+				output = chamelium_get_output_for_port(data,
+								       port);
+				pipe = chamelium_get_pipe_for_output(
+					&data->display, output);
+				mode = chamelium_get_mode_for_port(
+					data->chamelium, port);
+				chamelium_create_fb_for_mode(data, &fb, &mode);
+			}
+
+			igt_output_set_pipe(output, pipe);
+			chamelium_enable_output(data, port, output, &mode, &fb);
+		}
+
+		/* Now check if we get a hotplug from disconnection */
+		chamelium_unplug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF) {
+			igt_output_set_pipe(output, PIPE_NONE);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static const char test_hotplug_for_each_pipe_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug for each pipe with valid output";
+static void test_hotplug_for_each_pipe(chamelium_data_t *data,
+				       struct chamelium_port *port)
+{
+	igt_output_t *output;
+	enum pipe pipe;
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	/* Disconnect if any port got connected */
+	chamelium_unplug(data->chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_DISCONNECTED);
+
+	for_each_pipe(&data->display, pipe) {
+		igt_flush_uevents(mon);
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+		output = chamelium_get_output_for_port(data, port);
+
+		/* If pipe is valid for output then set it */
+		if (igt_pipe_connector_valid(pipe, output)) {
+			igt_output_set_pipe(output, pipe);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+
+		chamelium_unplug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+		igt_flush_uevents(mon);
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_suspend_resume_hpd_desc[] =
+	"Toggle HPD during suspend, check that uevents are sent and connector "
+	"status is updated";
+static void test_suspend_resume_hpd(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_suspend_state state,
+				    enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_suspend_resume_hpd_common_desc[] =
+	"Toggle HPD during suspend on all connectors, check that uevents are "
+	"sent and connector status is updated";
+static void test_suspend_resume_hpd_common(chamelium_data_t *data,
+					   enum igt_suspend_state state,
+					   enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	struct chamelium_port *port;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		port = data->ports[p];
+		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_without_ddc_desc[] =
+	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
+static void test_hpd_without_ddc(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+	igt_flush_uevents(mon);
+
+	/* Disable the DDC on the connector and make sure we still get a
+	 * hotplug
+	 */
+	chamelium_port_set_ddc_state(data->chamelium, port, false);
+	chamelium_plug(data->chamelium, port);
+
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_assert_eq(chamelium_reprobe_connector(&data->display,
+						  data->chamelium, port),
+		      DRM_MODE_CONNECTED);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_storm_detect_desc[] =
+	"Trigger a series of hotplugs in a very small timeframe to simulate a"
+	"bad cable, check the kernel falls back to polling to avoid a hotplug "
+	"storm";
+static void test_hpd_storm_detect(chamelium_data_t *data,
+				  struct chamelium_port *port, int width)
+{
+	struct udev_monitor *mon;
+	int count = 0;
+
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 1);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(igt_hpd_storm_detected(data->drm_fd));
+
+	mon = igt_watch_uevents();
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+
+	/*
+	 * Polling should have been enabled by the HPD storm at this point,
+	 * so we should only get at most 1 hotplug event
+	 */
+	igt_until_timeout(5)
+		count += igt_hotplug_detected(mon, 1);
+	igt_assert_lt(count, 2);
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_hpd_storm_disable_desc[] =
+	"Disable HPD storm detection, trigger a storm and check the kernel "
+	"doesn't detect one";
+static void test_hpd_storm_disable(chamelium_data_t *data,
+				   struct chamelium_port *port, int width)
+{
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
+
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-suspend", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("dp-hpd-storm", DisplayPort)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_DP);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("dp-hpd-storm-disable", DisplayPort)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_DP);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("hdmi-hpd-storm", HDMIA)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_HDMI);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_HDMI);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-enable-disable-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-with-enabled-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-suspend", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-hibernate", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_without_ddc_desc);
+		connector_subtest("vga-hpd-without-ddc", VGA)
+			test_hpd_without_ddc(&data, port);
+	}
+
+	igt_describe("Tests that operate on all connectors");
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(data.port_count);
+		}
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-suspend")
+			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
+						       SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-hibernate")
+			test_suspend_resume_hpd_common(&data,
+						       SUSPEND_STATE_DISK,
+						       SUSPEND_TEST_DEVICES);
+	}
+
+	igt_describe(test_hotplug_for_each_pipe_desc);
+	connector_subtest("vga-hpd-for-each-pipe", VGA)
+		test_hotplug_for_each_pipe(&data, port);
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 0d307730..6e5cc436 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
 # is too costly in comparison to the value
 # provided.
 ###############################################
-igt@kms_chamelium@hdmi-.*-planes-random
+igt@kms_chamelium_frames@hdmi-.*-planes-random
 ###############################################
 # Broadcom
 ###############################################
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index f57f8ff3..74e2524d 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
 igt@kms_addfb_basic@unused-offsets
 igt@kms_addfb_basic@unused-pitches
 igt@kms_busy@basic
-igt@kms_chamelium@dp-hpd-fast
-igt@kms_chamelium@dp-edid-read
-igt@kms_chamelium@dp-crc-fast
-igt@kms_chamelium@hdmi-hpd-fast
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@vga-hpd-fast
-igt@kms_chamelium@vga-edid-read
+igt@kms_chamelium_hdp@dp-hpd-fast
+igt@kms_chamelium_edid@dp-edid-read
+igt@kms_chamelium_frames@dp-crc-fast
+igt@kms_chamelium_hdp@hdmi-hpd-fast
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_hdp@vga-hpd-fast
+igt@kms_chamelium_edid@vga-edid-read
 igt@kms_prop_blob@basic
 igt@kms_cursor_legacy@basic-busy-flip-before-cursor
 igt@kms_cursor_legacy@basic-flip-after-cursor
@@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
 igt@i915_suspend@basic-s3-without-i915
 igt@gem_exec_suspend@basic-s0
 igt@gem_exec_suspend@basic-s3
-igt@kms_chamelium@common-hpd-after-suspend
+igt@kms_chamelium_hpd@common-hpd-after-suspend
 igt@kms_pipe_crc_basic@suspend-read-crc
diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
index f0ae30e3..f9242232 100644
--- a/tests/kms_color_helper.h
+++ b/tests/kms_color_helper.h
@@ -27,7 +27,7 @@
 
 /*
  * This header is for code that is shared between kms_color.c and
- * kms_color_chamelium.c. Reusability elsewhere can be questionable.
+ * kms_chamelium_color.c. Reusability elsewhere can be questionable.
  */
 
 #include <math.h>
diff --git a/tests/meson.build b/tests/meson.build
index 5c052e73..b52399d5 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -260,7 +260,10 @@ msm_progs = [
 ]
 
 chamelium_progs = [
-	'kms_chamelium',
+	'kms_chamelium_audio',
+	'kms_chamelium_edid',
+	'kms_chamelium_frames',
+	'kms_chamelium_hpd',
 ]
 
 test_deps = [ igt_deps ]
@@ -309,7 +312,8 @@ endforeach
 if chamelium.found()
 	foreach prog : chamelium_progs
 		test_executables += executable(prog,
-				 join_paths('chamelium', prog + '.c'),
+				 [join_paths('chamelium', prog + '.c'), 
+				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
 				 dependencies : test_deps,
 				 install_dir : libexecdir,
 				 install_rpath : libexecdir_rpathdir,
@@ -436,13 +440,13 @@ test_executables += executable('kms_color',
 test_list += 'kms_color'
 
 if chamelium.found()
-       test_executables += executable('kms_color_chamelium',
-                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
+       test_executables += executable('kms_chamelium_color',
+                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
                              dependencies : test_deps + [ chamelium ],
                              install_dir : libexecdir,
                              install_rpath : libexecdir_rpathdir,
                              install : true)
-       test_list += 'kms_color_chamelium'
+       test_list += 'kms_chamelium_color'
 endif
 
 test_executables += executable('sw_sync', 'sw_sync.c',
diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
index dd45d12a..a5521021 100644
--- a/tests/vc4_ci/vc4-chamelium-fast.testlist
+++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
@@ -1,14 +1,14 @@
-igt@kms_chamelium@hdmi-crc-abgr8888
-igt@kms_chamelium@hdmi-crc-argb1555
-igt@kms_chamelium@hdmi-crc-argb8888
-igt@kms_chamelium@hdmi-crc-bgr565
-igt@kms_chamelium@hdmi-crc-bgr888
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@hdmi-crc-rgb565
-igt@kms_chamelium@hdmi-crc-rgb888
-igt@kms_chamelium@hdmi-crc-xbgr8888
-igt@kms_chamelium@hdmi-crc-xrgb1555
-igt@kms_chamelium@hdmi-crc-xrgb8888
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-hpd
-igt@kms_chamelium@hdmi-hpd-fast
+igt@kms_chamelium_frames@hdmi-crc-abgr8888
+igt@kms_chamelium_frames@hdmi-crc-argb1555
+igt@kms_chamelium_frames@hdmi-crc-argb8888
+igt@kms_chamelium_frames@hdmi-crc-bgr565
+igt@kms_chamelium_frames@hdmi-crc-bgr888
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_frames@hdmi-crc-rgb565
+igt@kms_chamelium_frames@hdmi-crc-rgb888
+igt@kms_chamelium_frames@hdmi-crc-xbgr8888
+igt@kms_chamelium_frames@hdmi-crc-xrgb1555
+igt@kms_chamelium_frames@hdmi-crc-xrgb8888
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_hpd@hdmi-hpd
+igt@kms_chamelium_hpd@hdmi-hpd-fast
-- 
2.38.1.584.g0f3c55d4c2-goog

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
@ 2022-11-30 21:13 ` Patchwork
  2022-12-01 14:44   ` Petri Latvala
  2022-11-30 21:38 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Patchwork @ 2022-11-30 21:13 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests
URL   : https://patchwork.freedesktop.org/series/111501/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/751787 for the overview.

build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736079):
  ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
         drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
         ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    do { if (!(expr)) \
               ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    igt_assert(edid_blob =
                         ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    do { if (!(expr)) \
               ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669842325:step_script
  section_start:1669842325:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842326:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736074):
  ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    142 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669842333:step_script
  section_start:1669842333:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842334:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736078):
          uint32_t bpp;
          ^
  /usr/include/xf86drmMode.h:221:2: error: unknown type name 'uint32_t'
          uint32_t depth;
          ^
  /usr/include/xf86drmMode.h:223:2: error: unknown type name 'uint32_t'
          uint32_t handle;
          ^
  /usr/include/xf86drmMode.h:229:2: error: unknown type name 'uint32_t'
          uint32_t id;
          ^
  fatal error: too many errors emitted, stopping now [-ferror-limit=]
  20 errors generated.
  ninja: build stopped: subcommand failed.
  section_end:1669842399:step_script
  section_start:1669842399:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842399:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736077):
  ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    142 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669842332:step_script
  section_start:1669842332:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842333:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736075):
  ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    142 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669842333:step_script
  section_start:1669842333:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842334:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736076):
  ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    142 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669842334:step_script
  section_start:1669842334:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669842335:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/751787

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
  2022-11-30 21:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for " Patchwork
@ 2022-11-30 21:38 ` Patchwork
  2022-12-01  9:08 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-11-30 21:38 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 14838 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests
URL   : https://patchwork.freedesktop.org/series/111501/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12456 -> IGTPW_8177
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html

Participating hosts (36 -> 35)
------------------------------

  Additional (2): fi-kbl-7567u fi-hsw-4770 
  Missing    (3): fi-ilk-m540 bat-atsm-1 bat-dg1-6 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8177:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - {bat-jsl-1}:        NOTRUN -> [SKIP][1] +8 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {fi-jsl-1}:         NOTRUN -> [SKIP][2] +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {bat-rpls-1}:       NOTRUN -> [SKIP][3] +8 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-1/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_edid@vga-edid-read} (NEW):
    - fi-rkl-11600:       NOTRUN -> [SKIP][6] +7 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-rkl-11600/igt@kms_chamelium_edid@vga-edid-read.html
    - fi-icl-u2:          NOTRUN -> [SKIP][7] +8 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-icl-u2/igt@kms_chamelium_edid@vga-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - {bat-adlm-1}:       NOTRUN -> [SKIP][8] +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-adlm-1/igt@kms_chamelium_frames@dp-crc-fast.html
    - {bat-rplp-1}:       NOTRUN -> [SKIP][9] +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - {bat-adln-1}:       NOTRUN -> [SKIP][10] +8 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hdp@hdmi-hpd-fast} (NEW):
    - {bat-dg1-7}:        NOTRUN -> [SKIP][11] +8 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-dg1-7/igt@kms_chamelium_hdp@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hdp@vga-hpd-fast} (NEW):
    - {bat-adlp-6}:       NOTRUN -> [SKIP][12] +8 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-adlp-6/igt@kms_chamelium_hdp@vga-hpd-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - {bat-rpls-2}:       NOTRUN -> [SKIP][13] +8 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-2/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-rkl-guc:         NOTRUN -> [SKIP][14] +8 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-rkl-guc/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12456 and IGTPW_8177:

### New IGT tests (9) ###

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 1 pass(s) 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 1 pass(s) 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hdp@dp-hpd-fast:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hdp@hdmi-hpd-fast:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hdp@vga-hpd-fast:
    - Statuses : 35 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 1 pass(s) 31 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8177 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-7567u:       NOTRUN -> [SKIP][15] ([fdo#109271] / [i915#2190])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-kbl-7567u/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@basic:
    - fi-apl-guc:         NOTRUN -> [SKIP][16] ([fdo#109271] / [i915#4613]) +3 similar issues
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-apl-guc/igt@gem_lmem_swapping@basic.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][17] ([fdo#109271] / [i915#4613]) +3 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-kbl-7567u/igt@gem_lmem_swapping@basic.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - fi-ilk-650:         NOTRUN -> [SKIP][18] ([fdo#109271]) +8 similar issues
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-ilk-650/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-cfl-guc:         NOTRUN -> [SKIP][19] ([fdo#109271]) +8 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html
    - fi-glk-dsi:         NOTRUN -> [SKIP][20] ([fdo#109271]) +8 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-glk-dsi/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_edid@vga-edid-read} (NEW):
    - {bat-kbl-2}:        NOTRUN -> [SKIP][21] ([fdo#109271]) +8 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-kbl-2/igt@kms_chamelium_edid@vga-edid-read.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][22] ([fdo#109271]) +7 similar issues
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-bdw-gvtdvm/igt@kms_chamelium_edid@vga-edid-read.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][23] ([fdo#109271]) +8 similar issues
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-bsw-kefka/igt@kms_chamelium_edid@vga-edid-read.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - fi-kbl-x1275:       NOTRUN -> [SKIP][24] ([fdo#109271]) +8 similar issues
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-kbl-x1275/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-hsw-4770:        NOTRUN -> [SKIP][25] ([fdo#109271]) +20 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-hsw-4770/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-cfl-8109u:       NOTRUN -> [SKIP][26] ([fdo#109271]) +8 similar issues
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][27] ([fdo#109271]) +7 similar issues
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][28] ([fdo#109271]) +8 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-ivb-3770/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][29] ([fdo#109271]) +8 similar issues
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-elk-e7500/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hdp@dp-hpd-fast} (NEW):
    - fi-apl-guc:         NOTRUN -> [SKIP][30] ([fdo#109271]) +8 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-apl-guc/igt@kms_chamelium_hdp@dp-hpd-fast.html
    - fi-pnv-d510:        NOTRUN -> [SKIP][31] ([fdo#109271]) +8 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-pnv-d510/igt@kms_chamelium_hdp@dp-hpd-fast.html

  * {igt@kms_chamelium_hdp@hdmi-hpd-fast} (NEW):
    - fi-skl-6700k2:      NOTRUN -> [SKIP][32] ([fdo#109271]) +5 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-skl-6700k2/igt@kms_chamelium_hdp@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hdp@vga-hpd-fast} (NEW):
    - fi-cfl-8700k:       NOTRUN -> [SKIP][33] ([fdo#109271]) +8 similar issues
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-cfl-8700k/igt@kms_chamelium_hdp@vga-hpd-fast.html
    - fi-blb-e6850:       NOTRUN -> [SKIP][34] ([fdo#109271]) +8 similar issues
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-blb-e6850/igt@kms_chamelium_hdp@vga-hpd-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - fi-glk-j4005:       NOTRUN -> [SKIP][35] ([fdo#109271]) +8 similar issues
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-snb-2600:        NOTRUN -> [SKIP][36] ([fdo#109271]) +8 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-skl-guc:         NOTRUN -> [SKIP][37] ([fdo#109271]) +8 similar issues
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-skl-guc/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * igt@kms_psr@cursor_plane_move:
    - fi-kbl-7567u:       NOTRUN -> [SKIP][38] ([fdo#109271]) +39 similar issues
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-kbl-7567u/igt@kms_psr@cursor_plane_move.html

  * igt@kms_psr@sprite_plane_onoff:
    - fi-hsw-4770:        NOTRUN -> [SKIP][39] ([fdo#109271] / [i915#1072]) +3 similar issues
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-hsw-4770/igt@kms_psr@sprite_plane_onoff.html

  
#### Possible fixes ####

  * igt@core_hotunplug@unbind-rebind:
    - fi-apl-guc:         [INCOMPLETE][40] ([i915#7073]) -> [PASS][41]
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/fi-apl-guc/igt@core_hotunplug@unbind-rebind.html
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-apl-guc/igt@core_hotunplug@unbind-rebind.html

  * igt@fbdev@read:
    - {bat-rpls-2}:       [SKIP][42] ([i915#2582]) -> [PASS][43] +4 similar issues
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/bat-rpls-2/igt@fbdev@read.html
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-2/igt@fbdev@read.html

  * igt@gem_exec_gttfill@basic:
    - fi-pnv-d510:        [FAIL][44] ([i915#7229]) -> [PASS][45]
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
    - {bat-rpls-2}:       [DMESG-WARN][46] ([i915#6434]) -> [PASS][47] +1 similar issue
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/bat-rpls-2/igt@gem_exec_gttfill@basic.html
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-2/igt@gem_exec_gttfill@basic.html

  * igt@gem_exec_suspend@basic-s3@smem:
    - {bat-rpls-1}:       [DMESG-WARN][48] ([i915#6687]) -> [PASS][49]
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/bat-rpls-1/igt@gem_exec_suspend@basic-s3@smem.html
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-1/igt@gem_exec_suspend@basic-s3@smem.html

  * igt@i915_selftest@live@gt_lrc:
    - {bat-rpls-2}:       [INCOMPLETE][50] ([i915#4983]) -> [PASS][51]
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/bat-rpls-2/igt@i915_selftest@live@gt_lrc.html
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-2/igt@i915_selftest@live@gt_lrc.html

  * igt@i915_selftest@live@hangcheck:
    - fi-ivb-3770:        [INCOMPLETE][52] ([i915#3303] / [i915#7122]) -> [PASS][53]
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/fi-ivb-3770/igt@i915_selftest@live@hangcheck.html
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/fi-ivb-3770/igt@i915_selftest@live@hangcheck.html

  * igt@i915_selftest@live@slpc:
    - {bat-rpls-1}:       [DMESG-FAIL][54] ([i915#6367]) -> [PASS][55]
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/bat-rpls-1/igt@i915_selftest@live@slpc.html
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/bat-rpls-1/igt@i915_selftest@live@slpc.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#3303]: https://gitlab.freedesktop.org/drm/intel/issues/3303
  [i915#4258]: https://gitlab.freedesktop.org/drm/intel/issues/4258
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#6367]: https://gitlab.freedesktop.org/drm/intel/issues/6367
  [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
  [i915#6559]: https://gitlab.freedesktop.org/drm/intel/issues/6559
  [i915#6687]: https://gitlab.freedesktop.org/drm/intel/issues/6687
  [i915#7073]: https://gitlab.freedesktop.org/drm/intel/issues/7073
  [i915#7122]: https://gitlab.freedesktop.org/drm/intel/issues/7122
  [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
  [i915#7346]: https://gitlab.freedesktop.org/drm/intel/issues/7346


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7076 -> IGTPW_8177

  CI-20190529: 20190529
  CI_DRM_12456: 7a3c5315507ed0f4a9b0aa07ce6df1b3d28ebc35 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8177: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html
  IGT_7076: 888725538e0d6bbb94bbbb1ac278d4afcbbbdad0 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git


Testlist changes
----------------

+++ 71 lines
--- 71 lines

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html

[-- Attachment #2: Type: text/html, Size: 18116 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ Fi.CI.IGT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
  2022-11-30 21:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for " Patchwork
  2022-11-30 21:38 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
@ 2022-12-01  9:08 ` Patchwork
  2022-12-01 14:49 ` [igt-dev] [PATCH] " Petri Latvala
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-01  9:08 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 47922 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests
URL   : https://patchwork.freedesktop.org/series/111501/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_12456_full -> IGTPW_8177_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_8177_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_8177_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html

Participating hosts (11 -> 8)
------------------------------

  Missing    (3): pig-skl-6260u pig-kbl-iris pig-glk-j5005 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8177_full:

### IGT changes ###

#### Possible regressions ####

  * igt@i915_pm_rpm@fences:
    - shard-iclb:         [PASS][1] -> [INCOMPLETE][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb1/igt@i915_pm_rpm@fences.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@i915_pm_rpm@fences.html

  * {igt@kms_chamelium_edid@hdmi-edid-change-during-suspend} (NEW):
    - {shard-rkl}:        NOTRUN -> [SKIP][3] +48 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-4/igt@kms_chamelium_edid@hdmi-edid-change-during-suspend.html

  * {igt@kms_chamelium_frames@hdmi-cmp-planar-formats} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][4] +48 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_chamelium_frames@hdmi-cmp-planar-formats.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-storm-disable} (NEW):
    - {shard-dg1}:        NOTRUN -> [SKIP][5] +38 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-dg1-17/igt@kms_chamelium_hpd@hdmi-hpd-storm-disable.html

  * {igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][6] +49 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb7/igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12456_full and IGTPW_8177_full:

### New IGT tests (63) ###

  * igt@kms_chamelium_audio@dp-audio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@dp-audio-edid:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio-edid:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-25:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-50:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-75:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-blue-to-red:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-green-to-red:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-limited-range:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_color@ctm-max:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-negative:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-red-to-blue:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@degamma:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@gamma:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-change-during-suspend:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-resolution-list:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-non-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-mode-timings:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-change-during-suspend:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-4k:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-non-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-mode-timings:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-single:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-frame-dump:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-aspect-ratio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-cmp-planar-formats:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-nonplanar-formats:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-single:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-frame-dump:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@vga-frame-dump:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-after-suspend:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_hpd@dp-hpd-enable-disable-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-for-each-pipe:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm-disable:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_hpd@dp-hpd-with-enabled-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-after-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-enable-disable-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-for-each-pipe:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm-disable:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-with-enabled-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-after-suspend:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-enable-disable-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-for-each-pipe:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-without-ddc:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8177_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ccs@ctrl-surf-copy-new-ctx:
    - shard-iclb:         NOTRUN -> [SKIP][7] ([i915#5327])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@gem_ccs@ctrl-surf-copy-new-ctx.html
    - shard-tglb:         NOTRUN -> [SKIP][8] ([i915#5325])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@gem_ccs@ctrl-surf-copy-new-ctx.html

  * igt@gem_ctx_param@set-priority-not-supported:
    - shard-tglb:         NOTRUN -> [SKIP][9] ([fdo#109314])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@gem_ctx_param@set-priority-not-supported.html

  * igt@gem_ctx_persistence@engines-cleanup:
    - shard-snb:          NOTRUN -> [SKIP][10] ([fdo#109271] / [i915#1099])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-snb4/igt@gem_ctx_persistence@engines-cleanup.html

  * igt@gem_eio@unwedge-stress:
    - shard-snb:          NOTRUN -> [FAIL][11] ([i915#3354])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-snb7/igt@gem_eio@unwedge-stress.html

  * igt@gem_exec_balancer@parallel-bb-first:
    - shard-iclb:         [PASS][12] -> [SKIP][13] ([i915#4525]) +1 similar issue
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb1/igt@gem_exec_balancer@parallel-bb-first.html
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@gem_exec_balancer@parallel-bb-first.html

  * igt@gem_exec_capture@capture-invisible@smem0:
    - shard-tglb:         NOTRUN -> [SKIP][14] ([i915#6334])
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@gem_exec_capture@capture-invisible@smem0.html

  * igt@gem_exec_fair@basic-deadline:
    - shard-apl:          NOTRUN -> [FAIL][15] ([i915#2846])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl6/igt@gem_exec_fair@basic-deadline.html

  * igt@gem_exec_fair@basic-pace@vcs0:
    - shard-iclb:         [PASS][16] -> [FAIL][17] ([i915#2842])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb7/igt@gem_exec_fair@basic-pace@vcs0.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@gem_exec_fair@basic-pace@vcs0.html

  * igt@gem_exec_fair@basic-pace@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][18] ([i915#2842])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@gem_exec_fair@basic-pace@vcs1.html

  * igt@gem_exec_params@no-blt:
    - shard-tglb:         NOTRUN -> [SKIP][19] ([fdo#109283])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@gem_exec_params@no-blt.html

  * igt@gem_lmem_swapping@heavy-verify-random-ccs:
    - shard-tglb:         NOTRUN -> [SKIP][20] ([i915#4613]) +1 similar issue
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb5/igt@gem_lmem_swapping@heavy-verify-random-ccs.html

  * igt@gem_pxp@display-protected-crc:
    - shard-tglb:         NOTRUN -> [SKIP][21] ([i915#4270])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb3/igt@gem_pxp@display-protected-crc.html

  * igt@gem_render_copy@yf-tiled-mc-ccs-to-vebox-yf-tiled:
    - shard-iclb:         NOTRUN -> [SKIP][22] ([i915#768])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@gem_render_copy@yf-tiled-mc-ccs-to-vebox-yf-tiled.html

  * igt@gen9_exec_parse@bb-oversize:
    - shard-tglb:         NOTRUN -> [SKIP][23] ([i915#2527] / [i915#2856]) +1 similar issue
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb1/igt@gen9_exec_parse@bb-oversize.html

  * igt@gen9_exec_parse@unaligned-jump:
    - shard-iclb:         NOTRUN -> [SKIP][24] ([i915#2856])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@gen9_exec_parse@unaligned-jump.html

  * igt@i915_pipe_stress@stress-xrgb8888-ytiled:
    - shard-apl:          NOTRUN -> [FAIL][25] ([i915#7036])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl6/igt@i915_pipe_stress@stress-xrgb8888-ytiled.html

  * igt@i915_pm_lpsp@screens-disabled:
    - shard-tglb:         NOTRUN -> [SKIP][26] ([i915#1902])
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@i915_pm_lpsp@screens-disabled.html
    - shard-iclb:         NOTRUN -> [SKIP][27] ([i915#1902])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@i915_pm_lpsp@screens-disabled.html

  * igt@i915_pm_rc6_residency@media-rc6-accuracy:
    - shard-tglb:         NOTRUN -> [SKIP][28] ([fdo#109289]) +2 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@i915_pm_rc6_residency@media-rc6-accuracy.html
    - shard-iclb:         NOTRUN -> [SKIP][29] ([fdo#109289])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@i915_pm_rc6_residency@media-rc6-accuracy.html

  * igt@i915_pm_rpm@dpms-mode-unset-non-lpsp:
    - shard-tglb:         NOTRUN -> [SKIP][30] ([fdo#111644] / [i915#1397] / [i915#2411])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@i915_pm_rpm@dpms-mode-unset-non-lpsp.html

  * igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0:
    - shard-tglb:         NOTRUN -> [SKIP][31] ([i915#5286]) +3 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0.html
    - shard-iclb:         NOTRUN -> [SKIP][32] ([i915#5286]) +2 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0.html

  * igt@kms_big_fb@x-tiled-32bpp-rotate-90:
    - shard-tglb:         NOTRUN -> [SKIP][33] ([fdo#111614])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@kms_big_fb@x-tiled-32bpp-rotate-90.html
    - shard-iclb:         NOTRUN -> [SKIP][34] ([fdo#110725] / [fdo#111614])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_big_fb@x-tiled-32bpp-rotate-90.html

  * igt@kms_big_fb@yf-tiled-8bpp-rotate-270:
    - shard-tglb:         NOTRUN -> [SKIP][35] ([fdo#111615]) +3 similar issues
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_big_fb@yf-tiled-8bpp-rotate-270.html

  * igt@kms_ccs@pipe-a-bad-pixel-format-4_tiled_dg2_mc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][36] ([i915#6095]) +3 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb7/igt@kms_ccs@pipe-a-bad-pixel-format-4_tiled_dg2_mc_ccs.html

  * igt@kms_ccs@pipe-b-bad-pixel-format-y_tiled_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][37] ([i915#3689]) +6 similar issues
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb3/igt@kms_ccs@pipe-b-bad-pixel-format-y_tiled_ccs.html

  * igt@kms_ccs@pipe-c-missing-ccs-buffer-y_tiled_gen12_mc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][38] ([i915#3689] / [i915#3886])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb7/igt@kms_ccs@pipe-c-missing-ccs-buffer-y_tiled_gen12_mc_ccs.html

  * igt@kms_ccs@pipe-d-bad-rotation-90-yf_tiled_ccs:
    - shard-iclb:         NOTRUN -> [SKIP][39] ([fdo#109278]) +10 similar issues
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb1/igt@kms_ccs@pipe-d-bad-rotation-90-yf_tiled_ccs.html

  * igt@kms_ccs@pipe-d-missing-ccs-buffer-yf_tiled_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][40] ([fdo#111615] / [i915#3689]) +6 similar issues
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@kms_ccs@pipe-d-missing-ccs-buffer-yf_tiled_ccs.html

  * {igt@kms_chamelium_color@ctm-0-75} (NEW):
    - shard-apl:          NOTRUN -> [SKIP][41] ([fdo#109271]) +113 similar issues
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl7/igt@kms_chamelium_color@ctm-0-75.html

  * {igt@kms_chamelium_color@ctm-green-to-red} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][42] ([fdo#109284]) +9 similar issues
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb6/igt@kms_chamelium_color@ctm-green-to-red.html

  * {igt@kms_chamelium_color@gamma} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][43] ([fdo#109284]) +9 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_chamelium_color@gamma.html

  * igt@kms_color@ctm-0-25@pipe-c-edp-1:
    - shard-tglb:         NOTRUN -> [FAIL][44] ([i915#315] / [i915#6946]) +3 similar issues
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_color@ctm-0-25@pipe-c-edp-1.html

  * igt@kms_cursor_crc@cursor-offscreen-32x32:
    - shard-tglb:         NOTRUN -> [SKIP][45] ([i915#3555]) +2 similar issues
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb5/igt@kms_cursor_crc@cursor-offscreen-32x32.html

  * igt@kms_cursor_crc@cursor-random-512x512:
    - shard-tglb:         NOTRUN -> [SKIP][46] ([i915#3359])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb3/igt@kms_cursor_crc@cursor-random-512x512.html

  * igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy:
    - shard-tglb:         NOTRUN -> [SKIP][47] ([fdo#109274] / [fdo#111825]) +2 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy.html

  * igt@kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic:
    - shard-iclb:         NOTRUN -> [SKIP][48] ([fdo#109274]) +3 similar issues
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb3/igt@kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic.html

  * igt@kms_cursor_legacy@cursor-vs-flip@varying-size:
    - shard-iclb:         [PASS][49] -> [FAIL][50] ([i915#5072])
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb6/igt@kms_cursor_legacy@cursor-vs-flip@varying-size.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@kms_cursor_legacy@cursor-vs-flip@varying-size.html

  * igt@kms_flip@2x-plain-flip:
    - shard-tglb:         NOTRUN -> [SKIP][51] ([fdo#109274] / [fdo#111825] / [i915#3637]) +5 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@kms_flip@2x-plain-flip.html

  * igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-32bpp-4tiledg2rcccs-downscaling@pipe-a-valid-mode:
    - shard-iclb:         NOTRUN -> [SKIP][52] ([i915#2587] / [i915#2672]) +3 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-32bpp-4tiledg2rcccs-downscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-downscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][53] ([i915#6375])
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-downscaling@pipe-a-default-mode.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-64bpp-yftile-upscaling@pipe-a-valid-mode:
    - shard-tglb:         NOTRUN -> [SKIP][54] ([i915#2587] / [i915#2672]) +1 similar issue
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-64bpp-yftile-upscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-downscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][55] ([i915#2672] / [i915#3555])
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb3/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-downscaling@pipe-a-default-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][56] ([i915#2672]) +1 similar issue
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling@pipe-a-default-mode.html

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt:
    - shard-iclb:         [PASS][57] -> [FAIL][58] ([i915#2546])
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt.html
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt.html

  * igt@kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary:
    - shard-tglb:         NOTRUN -> [SKIP][59] ([i915#6497]) +7 similar issues
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb1/igt@kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-mmap-wc:
    - shard-snb:          NOTRUN -> [SKIP][60] ([fdo#109271]) +146 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-snb7/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-pwrite:
    - shard-tglb:         NOTRUN -> [SKIP][61] ([fdo#109280] / [fdo#111825]) +17 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb5/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-pwrite.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-shrfb-pgflip-blt:
    - shard-iclb:         NOTRUN -> [SKIP][62] ([fdo#109280]) +12 similar issues
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-shrfb-pgflip-blt.html

  * igt@kms_psr2_sf@cursor-plane-update-sf:
    - shard-apl:          NOTRUN -> [SKIP][63] ([fdo#109271] / [i915#658]) +1 similar issue
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl2/igt@kms_psr2_sf@cursor-plane-update-sf.html
    - shard-tglb:         NOTRUN -> [SKIP][64] ([i915#2920])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@kms_psr2_sf@cursor-plane-update-sf.html
    - shard-iclb:         NOTRUN -> [SKIP][65] ([fdo#111068] / [i915#658])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@kms_psr2_sf@cursor-plane-update-sf.html

  * igt@kms_psr2_su@page_flip-xrgb8888:
    - shard-iclb:         NOTRUN -> [SKIP][66] ([fdo#109642] / [fdo#111068] / [i915#658])
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@kms_psr2_su@page_flip-xrgb8888.html
    - shard-tglb:         NOTRUN -> [SKIP][67] ([i915#7037])
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@kms_psr2_su@page_flip-xrgb8888.html

  * igt@kms_psr@psr2_cursor_mmap_gtt:
    - shard-tglb:         NOTRUN -> [FAIL][68] ([i915#132] / [i915#3467])
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb6/igt@kms_psr@psr2_cursor_mmap_gtt.html

  * igt@kms_psr@psr2_sprite_plane_move:
    - shard-iclb:         [PASS][69] -> [SKIP][70] ([fdo#109441]) +2 similar issues
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb2/igt@kms_psr@psr2_sprite_plane_move.html
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@kms_psr@psr2_sprite_plane_move.html

  * igt@kms_psr_stress_test@flip-primary-invalidate-overlay:
    - shard-tglb:         NOTRUN -> [SKIP][71] ([i915#5519])
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb5/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html

  * igt@kms_setmode@invalid-clone-exclusive-crtc:
    - shard-iclb:         NOTRUN -> [SKIP][72] ([i915#3555]) +2 similar issues
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb5/igt@kms_setmode@invalid-clone-exclusive-crtc.html

  * igt@prime_vgem@fence-read-hang:
    - shard-iclb:         NOTRUN -> [SKIP][73] ([fdo#109295]) +1 similar issue
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb6/igt@prime_vgem@fence-read-hang.html
    - shard-tglb:         NOTRUN -> [SKIP][74] ([fdo#109295]) +1 similar issue
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@prime_vgem@fence-read-hang.html

  * igt@sysfs_clients@fair-7:
    - shard-apl:          NOTRUN -> [SKIP][75] ([fdo#109271] / [i915#2994])
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl8/igt@sysfs_clients@fair-7.html
    - shard-tglb:         NOTRUN -> [SKIP][76] ([i915#2994]) +2 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb1/igt@sysfs_clients@fair-7.html
    - shard-iclb:         NOTRUN -> [SKIP][77] ([i915#2994])
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@sysfs_clients@fair-7.html

  
#### Possible fixes ####

  * igt@gem_ctx_exec@basic-nohangcheck:
    - {shard-rkl}:        [FAIL][78] ([i915#6268]) -> [PASS][79]
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-4/igt@gem_ctx_exec@basic-nohangcheck.html
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-1/igt@gem_ctx_exec@basic-nohangcheck.html
    - shard-tglb:         [FAIL][80] ([i915#6268]) -> [PASS][81]
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-tglb3/igt@gem_ctx_exec@basic-nohangcheck.html
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb7/igt@gem_ctx_exec@basic-nohangcheck.html

  * igt@gem_eio@in-flight-contexts-10ms:
    - {shard-rkl}:        [TIMEOUT][82] ([i915#3063]) -> [PASS][83]
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-3/igt@gem_eio@in-flight-contexts-10ms.html
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-1/igt@gem_eio@in-flight-contexts-10ms.html

  * igt@gem_eio@in-flight-suspend:
    - {shard-rkl}:        [FAIL][84] ([fdo#103375]) -> [PASS][85] +1 similar issue
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-4/igt@gem_eio@in-flight-suspend.html
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-6/igt@gem_eio@in-flight-suspend.html

  * igt@gem_eio@suspend:
    - {shard-rkl}:        [FAIL][86] ([i915#7052]) -> [PASS][87]
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-3/igt@gem_eio@suspend.html
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-1/igt@gem_eio@suspend.html

  * igt@gem_exec_balancer@parallel-contexts:
    - shard-iclb:         [SKIP][88] ([i915#4525]) -> [PASS][89]
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb5/igt@gem_exec_balancer@parallel-contexts.html
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb1/igt@gem_exec_balancer@parallel-contexts.html

  * igt@gem_exec_fair@basic-pace-share@rcs0:
    - shard-tglb:         [FAIL][90] ([i915#2842]) -> [PASS][91]
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-tglb1/igt@gem_exec_fair@basic-pace-share@rcs0.html
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb2/igt@gem_exec_fair@basic-pace-share@rcs0.html

  * igt@gem_exec_fair@basic-pace@vecs0:
    - shard-iclb:         [FAIL][92] ([i915#2842]) -> [PASS][93]
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb7/igt@gem_exec_fair@basic-pace@vecs0.html
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@gem_exec_fair@basic-pace@vecs0.html

  * igt@gem_exec_reloc@basic-wc-gtt-active:
    - {shard-rkl}:        [SKIP][94] ([i915#3281]) -> [PASS][95] +2 similar issues
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-3/igt@gem_exec_reloc@basic-wc-gtt-active.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-5/igt@gem_exec_reloc@basic-wc-gtt-active.html

  * igt@gem_ppgtt@blt-vs-render-ctxn:
    - {shard-rkl}:        [FAIL][96] ([i915#3692] / [i915#4998]) -> [PASS][97]
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-5/igt@gem_ppgtt@blt-vs-render-ctxn.html
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-1/igt@gem_ppgtt@blt-vs-render-ctxn.html

  * igt@gem_pread@self:
    - {shard-rkl}:        [SKIP][98] ([i915#3282]) -> [PASS][99]
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-4/igt@gem_pread@self.html
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-5/igt@gem_pread@self.html

  * igt@gen9_exec_parse@allowed-all:
    - shard-apl:          [DMESG-WARN][100] ([i915#5566] / [i915#716]) -> [PASS][101]
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl1/igt@gen9_exec_parse@allowed-all.html
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl3/igt@gen9_exec_parse@allowed-all.html

  * igt@gen9_exec_parse@bb-start-out:
    - {shard-rkl}:        [SKIP][102] ([i915#2527]) -> [PASS][103]
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-1/igt@gen9_exec_parse@bb-start-out.html
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-5/igt@gen9_exec_parse@bb-start-out.html

  * igt@i915_pm_dc@dc6-dpms:
    - {shard-rkl}:        [SKIP][104] ([i915#3361]) -> [PASS][105]
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-5/igt@i915_pm_dc@dc6-dpms.html
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-4/igt@i915_pm_dc@dc6-dpms.html

  * igt@kms_ccs@pipe-b-bad-aux-stride-y_tiled_gen12_rc_ccs:
    - {shard-rkl}:        [SKIP][106] ([i915#1845] / [i915#4098]) -> [PASS][107] +12 similar issues
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-3/igt@kms_ccs@pipe-b-bad-aux-stride-y_tiled_gen12_rc_ccs.html
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-6/igt@kms_ccs@pipe-b-bad-aux-stride-y_tiled_gen12_rc_ccs.html

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-gtt:
    - {shard-rkl}:        [SKIP][108] ([i915#1849] / [i915#4098]) -> [PASS][109] +10 similar issues
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-1/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-gtt.html
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-6/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-gtt.html

  * igt@kms_plane@plane-panning-bottom-right-suspend@pipe-a-planes:
    - {shard-rkl}:        [SKIP][110] ([i915#3558]) -> [PASS][111] +1 similar issue
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-4/igt@kms_plane@plane-panning-bottom-right-suspend@pipe-a-planes.html
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-6/igt@kms_plane@plane-panning-bottom-right-suspend@pipe-a-planes.html

  * igt@kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5@pipe-b-edp-1:
    - shard-iclb:         [SKIP][112] ([i915#5235]) -> [PASS][113] +2 similar issues
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb2/igt@kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5@pipe-b-edp-1.html
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb6/igt@kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5@pipe-b-edp-1.html

  * igt@kms_psr@psr2_primary_blt:
    - shard-iclb:         [SKIP][114] ([fdo#109441]) -> [PASS][115] +1 similar issue
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb8/igt@kms_psr@psr2_primary_blt.html
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_psr@psr2_primary_blt.html

  * igt@perf@gen12-mi-rpc:
    - {shard-rkl}:        [SKIP][116] ([fdo#109289]) -> [PASS][117]
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-rkl-5/igt@perf@gen12-mi-rpc.html
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-rkl-6/igt@perf@gen12-mi-rpc.html

  * igt@perf_pmu@enable-race@rcs0:
    - shard-tglb:         [INCOMPLETE][118] ([i915#6453]) -> [PASS][119]
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-tglb7/igt@perf_pmu@enable-race@rcs0.html
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb3/igt@perf_pmu@enable-race@rcs0.html

  * igt@sysfs_heartbeat_interval@precise@rcs0:
    - {shard-dg1}:        [FAIL][120] ([i915#1755]) -> [PASS][121]
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-dg1-15/igt@sysfs_heartbeat_interval@precise@rcs0.html
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-dg1-19/igt@sysfs_heartbeat_interval@precise@rcs0.html

  
#### Warnings ####

  * igt@gem_exec_balancer@parallel-ordering:
    - shard-iclb:         [FAIL][122] ([i915#6117]) -> [SKIP][123] ([i915#4525])
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb1/igt@gem_exec_balancer@parallel-ordering.html
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb7/igt@gem_exec_balancer@parallel-ordering.html

  * igt@gem_pread@exhaustion:
    - shard-tglb:         [INCOMPLETE][124] ([i915#7248]) -> [WARN][125] ([i915#2658]) +1 similar issue
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-tglb5/igt@gem_pread@exhaustion.html
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-tglb8/igt@gem_pread@exhaustion.html

  * igt@gem_pwrite@basic-exhaustion:
    - shard-apl:          [INCOMPLETE][126] ([i915#7248]) -> [WARN][127] ([i915#2658])
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl7/igt@gem_pwrite@basic-exhaustion.html
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl1/igt@gem_pwrite@basic-exhaustion.html

  * igt@kms_fbcon_fbt@fbc-suspend:
    - shard-apl:          [FAIL][128] ([i915#4767]) -> [INCOMPLETE][129] ([i915#180])
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl3/igt@kms_fbcon_fbt@fbc-suspend.html
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl3/igt@kms_fbcon_fbt@fbc-suspend.html

  * igt@kms_psr2_sf@cursor-plane-move-continuous-sf:
    - shard-iclb:         [SKIP][130] ([i915#658]) -> [SKIP][131] ([i915#2920])
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb8/igt@kms_psr2_sf@cursor-plane-move-continuous-sf.html
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb2/igt@kms_psr2_sf@cursor-plane-move-continuous-sf.html

  * igt@kms_psr2_sf@overlay-plane-move-continuous-exceed-fully-sf:
    - shard-iclb:         [SKIP][132] ([i915#2920]) -> [SKIP][133] ([i915#658])
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb2/igt@kms_psr2_sf@overlay-plane-move-continuous-exceed-fully-sf.html
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb8/igt@kms_psr2_sf@overlay-plane-move-continuous-exceed-fully-sf.html

  * igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area:
    - shard-iclb:         [SKIP][134] ([i915#2920]) -> [SKIP][135] ([fdo#111068] / [i915#658])
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-iclb2/igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area.html
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-iclb6/igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area.html

  * igt@runner@aborted:
    - shard-apl:          ([FAIL][136], [FAIL][137], [FAIL][138]) ([fdo#109271] / [i915#3002] / [i915#4312]) -> ([FAIL][139], [FAIL][140], [FAIL][141]) ([i915#180] / [i915#3002] / [i915#4312])
   [136]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl2/igt@runner@aborted.html
   [137]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl3/igt@runner@aborted.html
   [138]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12456/shard-apl1/igt@runner@aborted.html
   [139]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl6/igt@runner@aborted.html
   [140]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl3/igt@runner@aborted.html
   [141]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/shard-apl3/igt@runner@aborted.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103375]: https://bugs.freedesktop.org/show_bug.cgi?id=103375
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109283]: https://bugs.freedesktop.org/show_bug.cgi?id=109283
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109291]: https://bugs.freedesktop.org/show_bug.cgi?id=109291
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [fdo#109300]: https://bugs.freedesktop.org/show_bug.cgi?id=109300
  [fdo#109308]: https://bugs.freedesktop.org/show_bug.cgi?id=109308
  [fdo#109313]: https://bugs.freedesktop.org/show_bug.cgi?id=109313
  [fdo#109314]: https://bugs.freedesktop.org/show_bug.cgi?id=109314
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109506]: https://bugs.freedesktop.org/show_bug.cgi?id=109506
  [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
  [fdo#110542]: https://bugs.freedesktop.org/show_bug.cgi?id=110542
  [fdo#110723]: https://bugs.freedesktop.org/show_bug.cgi?id=110723
  [fdo#110725]: https://bugs.freedesktop.org/show_bug.cgi?id=110725
  [fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068
  [fdo#111614]: https://bugs.freedesktop.org/show_bug.cgi?id=111614
  [fdo#111615]: https://bugs.freedesktop.org/show_bug.cgi?id=111615
  [fdo#111644]: https://bugs.freedesktop.org/show_bug.cgi?id=111644
  [fdo#111825]: https://bugs.freedesktop.org/show_bug.cgi?id=111825
  [fdo#112054]: https://bugs.freedesktop.org/show_bug.cgi?id=112054
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1099]: https://gitlab.freedesktop.org/drm/intel/issues/1099
  [i915#132]: https://gitlab.freedesktop.org/drm/intel/issues/132
  [i915#1397]: https://gitlab.freedesktop.org/drm/intel/issues/1397
  [i915#1755]: https://gitlab.freedesktop.org/drm/intel/issues/1755
  [i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180
  [i915#1825]: https://gitlab.freedesktop.org/drm/intel/issues/1825
  [i915#1839]: https://gitlab.freedesktop.org/drm/intel/issues/1839
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
  [i915#1902]: https://gitlab.freedesktop.org/drm/intel/issues/1902
  [i915#2411]: https://gitlab.freedesktop.org/drm/intel/issues/2411
  [i915#2437]: https://gitlab.freedesktop.org/drm/intel/issues/2437
  [i915#2527]: https://gitlab.freedesktop.org/drm/intel/issues/2527
  [i915#2546]: https://gitlab.freedesktop.org/drm/intel/issues/2546
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2587]: https://gitlab.freedesktop.org/drm/intel/issues/2587
  [i915#2658]: https://gitlab.freedesktop.org/drm/intel/issues/2658
  [i915#2672]: https://gitlab.freedesktop.org/drm/intel/issues/2672
  [i915#280]: https://gitlab.freedesktop.org/drm/intel/issues/280
  [i915#2842]: https://gitlab.freedesktop.org/drm/intel/issues/2842
  [i915#2846]: https://gitlab.freedesktop.org/drm/intel/issues/2846
  [i915#2856]: https://gitlab.freedesktop.org/drm/intel/issues/2856
  [i915#2920]: https://gitlab.freedesktop.org/drm/intel/issues/2920
  [i915#2994]: https://gitlab.freedesktop.org/drm/intel/issues/2994
  [i915#3002]: https://gitlab.freedesktop.org/drm/intel/issues/3002
  [i915#3063]: https://gitlab.freedesktop.org/drm/intel/issues/3063
  [i915#3116]: https://gitlab.freedesktop.org/drm/intel/issues/3116
  [i915#315]: https://gitlab.freedesktop.org/drm/intel/issues/315
  [i915#3281]: https://gitlab.freedesktop.org/drm/intel/issues/3281
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3297]: https://gitlab.freedesktop.org/drm/intel/issues/3297
  [i915#3354]: https://gitlab.freedesktop.org/drm/intel/issues/3354
  [i915#3359]: https://gitlab.freedesktop.org/drm/intel/issues/3359
  [i915#3361]: https://gitlab.freedesktop.org/drm/intel/issues/3361
  [i915#3458]: https://gitlab.freedesktop.org/drm/intel/issues/3458
  [i915#3467]: https://gitlab.freedesktop.org/drm/intel/issues/3467
  [i915#3539]: https://gitlab.freedesktop.org/drm/intel/issues/3539
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3558]: https://gitlab.freedesktop.org/drm/intel/issues/3558
  [i915#3637]: https://gitlab.freedesktop.org/drm/intel/issues/3637
  [i915#3638]: https://gitlab.freedesktop.org/drm/intel/issues/3638
  [i915#3689]: https://gitlab.freedesktop.org/drm/intel/issues/3689
  [i915#3692]: https://gitlab.freedesktop.org/drm/intel/issues/3692
  [i915#3734]: https://gitlab.freedesktop.org/drm/intel/issues/3734
  [i915#3742]: https://gitlab.freedesktop.org/drm/intel/issues/3742
  [i915#3810]: https://gitlab.freedesktop.org/drm/intel/issues/3810
  [i915#3840]: https://gitlab.freedesktop.org/drm/intel/issues/3840
  [i915#3886]: https://gitlab.freedesktop.org/drm/intel/issues/3886
  [i915#3955]: https://gitlab.freedesktop.org/drm/intel/issues/3955
  [i915#4070]: https://gitlab.freedesktop.org/drm/intel/issues/4070
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4098]: https://gitlab.freedesktop.org/drm/intel/issues/4098
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4270]: https://gitlab.freedesktop.org/drm/intel/issues/4270
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#433]: https://gitlab.freedesktop.org/drm/intel/issues/433
  [i915#4349]: https://gitlab.freedesktop.org/drm/intel/issues/4349
  [i915#4391]: https://gitlab.freedesktop.org/drm/intel/issues/4391
  [i915#4525]: https://gitlab.freedesktop.org/drm/intel/issues/4525
  [i915#4538]: https://gitlab.freedesktop.org/drm/intel/issues/4538
  [i915#4565]: https://gitlab.freedesktop.org/drm/intel/issues/4565
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4767]: https://gitlab.freedesktop.org/drm/intel/issues/4767
  [i915#4771]: https://gitlab.freedesktop.org/drm/intel/issues/4771
  [i915#4812]: https://gitlab.freedesktop.org/drm/intel/issues/4812
  [i915#4833]: https://gitlab.freedesktop.org/drm/intel/issues/4833
  [i915#4852]: https://gitlab.freedesktop.org/drm/intel/issues/4852
  [i915#4860]: https://gitlab.freedesktop.org/drm/intel/issues/4860
  [i915#4877]: https://gitlab.freedesktop.org/drm/intel/issues/4877
  [i915#4879]: https://gitlab.freedesktop.org/drm/intel/issues/4879
  [i915#4881]: https://gitlab.freedesktop.org/drm/intel/issues/4881
  [i915#4958]: https://gitlab.freedesktop.org/drm/intel/issues/4958
  [i915#4998]: https://gitlab.freedesktop.org/drm/intel/issues/4998
  [i915#5030]: https://gitlab.freedesktop.org/drm/intel/issues/5030
  [i915#5072]: https://gitlab.freedesktop.org/drm/intel/issues/5072
  [i915#5176]: https://gitlab.freedesktop.org/drm/intel/issues/5176
  [i915#5234]: https://gitlab.freedesktop.org/drm/intel/issues/5234
  [i915#5235]: https://gitlab.freedesktop.org/drm/intel/issues/5235
  [i915#5286]: https://gitlab.freedesktop.org/drm/intel/issues/5286
  [i915#5288]: https://gitlab.freedesktop.org/drm/intel/issues/5288
  [i915#5289]: https://gitlab.freedesktop.org/drm/intel/issues/5289
  [i915#5325]: https://gitlab.freedesktop.org/drm/intel/issues/5325
  [i915#5327]: https://gitlab.freedesktop.org/drm/intel/issues/5327
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#5439]: https://gitlab.freedesktop.org/drm/intel/issues/5439
  [i915#5461]: https://gitlab.freedesktop.org/drm/intel/issues/5461
  [i915#5519]: https://gitlab.freedesktop.org/drm/intel/issues/5519
  [i915#5563]: https://gitlab.freedesktop.org/drm/intel/issues/5563
  [i915#5566]: https://gitlab.freedesktop.org/drm/intel/issues/5566
  [i915#6095]: https://gitlab.freedesktop.org/drm/intel/issues/6095
  [i915#6117]: https://gitlab.freedesktop.org/drm/intel/issues/6117
  [i915#6159]: https://gitlab.freedesktop.org/drm/intel/issues/6159
  [i915#6230]: https://gitlab.freedesktop.org/drm/intel/issues/6230
  [i915#6248]: https://gitlab.freedesktop.org/drm/intel/issues/6248
  [i915#6268]: https://gitlab.freedesktop.org/drm/intel/issues/6268
  [i915#6301]: https://gitlab.freedesktop.org/drm/intel/issues/6301
  [i915#6334]: https://gitlab.freedesktop.org/drm/intel/issues/6334
  [i915#6375]: https://gitlab.freedesktop.org/drm/intel/issues/6375
  [i915#6412]: https://gitlab.freedesktop.org/drm/intel/issues/6412
  [i915#6433]: https://gitlab.freedesktop.org/drm/intel/issues/6433
  [i915#6453]: https://gitlab.freedesktop.org/drm/intel/issues/6453
  [i915#6463]: https://gitlab.freedesktop.org/drm/intel/issues/6463
  [i915#6497]: https://gitlab.freedesktop.org/drm/intel/issues/6497
  [i915#6524]: https://gitlab.freedesktop.org/drm/intel/issues/6524
  [i915#658]: https://gitlab.freedesktop.org/drm/intel/issues/658
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6768]: https://gitlab.freedesktop.org/drm/intel/issues/6768
  [i915#6946]: https://gitlab.freedesktop.org/drm/intel/issues/6946
  [i915#7036]: https://gitlab.freedesktop.org/drm/intel/issues/7036
  [i915#7037]: https://gitlab.freedesktop.org/drm/intel/issues/7037
  [i915#7052]: https://gitlab.freedesktop.org/drm/intel/issues/7052
  [i915#7116]: https://gitlab.freedesktop.org/drm/intel/issues/7116
  [i915#7118]: https://gitlab.freedesktop.org/drm/intel/issues/7118
  [i915#716]: https://gitlab.freedesktop.org/drm/intel/issues/716
  [i915#7178]: https://gitlab.freedesktop.org/drm/intel/issues/7178
  [i915#7248]: https://gitlab.freedesktop.org/drm/intel/issues/7248
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
  [i915#7582]: https://gitlab.freedesktop.org/drm/intel/issues/7582
  [i915#768]: https://gitlab.freedesktop.org/drm/intel/issues/768


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7076 -> IGTPW_8177
  * Piglit: piglit_4509 -> None

  CI-20190529: 20190529
  CI_DRM_12456: 7a3c5315507ed0f4a9b0aa07ce6df1b3d28ebc35 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8177: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html
  IGT_7076: 888725538e0d6bbb94bbbb1ac278d4afcbbbdad0 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8177/index.html

[-- Attachment #2: Type: text/html, Size: 52554 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 21:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for " Patchwork
@ 2022-12-01 14:44   ` Petri Latvala
  0 siblings, 0 replies; 25+ messages in thread
From: Petri Latvala @ 2022-12-01 14:44 UTC (permalink / raw)
  To: igt-dev

On Wed, Nov 30, 2022 at 09:13:15PM +0000, Patchwork wrote:
> == Series Details ==
> 
> Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests
> URL   : https://patchwork.freedesktop.org/series/111501/
> State : warning
> 
> == Summary ==
> 
> Pipeline status: FAILED.
> 
> see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/751787 for the overview.
> 
> build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736079):
>   ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
>          drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
>          ^~~~~~~~~~~~~~~~~~~~~~

Are you missing an #include in kms_chamelium_edid.c?


-- 
Petri Latvala





>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     do { if (!(expr)) \
>                ^~~~
>   ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
>     igt_assert(edid_blob =
>                          ^
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     do { if (!(expr)) \
>                ^~~~
>   cc1: some warnings being treated as errors
>   ninja: build stopped: subcommand failed.
>   section_end:1669842325:step_script
>   section_start:1669842325:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842326:cleanup_file_variables
>   ERROR: Job failed: exit code 1
>   
> 
> build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736074):
>   ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
>     143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
>         |       ^~~~~~~~~~~~~~~~~~~~~~
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
>     142 |  igt_assert(edid_blob =
>         |                       ^
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   cc1: some warnings being treated as errors
>   ninja: build stopped: subcommand failed.
>   section_end:1669842333:step_script
>   section_start:1669842333:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842334:cleanup_file_variables
>   ERROR: Job failed: exit code 1
>   
> 
> build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736078):
>           uint32_t bpp;
>           ^
>   /usr/include/xf86drmMode.h:221:2: error: unknown type name 'uint32_t'
>           uint32_t depth;
>           ^
>   /usr/include/xf86drmMode.h:223:2: error: unknown type name 'uint32_t'
>           uint32_t handle;
>           ^
>   /usr/include/xf86drmMode.h:229:2: error: unknown type name 'uint32_t'
>           uint32_t id;
>           ^
>   fatal error: too many errors emitted, stopping now [-ferror-limit=]
>   20 errors generated.
>   ninja: build stopped: subcommand failed.
>   section_end:1669842399:step_script
>   section_start:1669842399:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842399:cleanup_file_variables
>   ERROR: Job failed: exit code 1
>   
> 
> build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736077):
>   ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
>     143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
>         |       ^~~~~~~~~~~~~~~~~~~~~~
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
>     142 |  igt_assert(edid_blob =
>         |                       ^
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   cc1: some warnings being treated as errors
>   ninja: build stopped: subcommand failed.
>   section_end:1669842332:step_script
>   section_start:1669842332:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842333:cleanup_file_variables
>   ERROR: Job failed: exit code 1
>   
> 
> build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736075):
>   ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
>     143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
>         |       ^~~~~~~~~~~~~~~~~~~~~~
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
>     142 |  igt_assert(edid_blob =
>         |                       ^
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   cc1: some warnings being treated as errors
>   ninja: build stopped: subcommand failed.
>   section_end:1669842333:step_script
>   section_start:1669842333:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842334:cleanup_file_variables
>   ERROR: Job failed: exit code 1
>   
> 
> build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32736076):
>   ../tests/chamelium/kms_chamelium_edid.c:143:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
>     143 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
>         |       ^~~~~~~~~~~~~~~~~~~~~~
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   ../tests/chamelium/kms_chamelium_edid.c:142:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
>     142 |  igt_assert(edid_blob =
>         |                       ^
>   ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
>     676 |  do { if (!(expr)) \
>         |             ^~~~
>   cc1: some warnings being treated as errors
>   ninja: build stopped: subcommand failed.
>   section_end:1669842334:step_script
>   section_start:1669842334:cleanup_file_variables
>   Cleaning up project directory and file based variables
>   section_end:1669842335:cleanup_file_variables
>   ERROR: Job failed: exit code 1
> 
> == Logs ==
> 
> For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/751787

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (2 preceding siblings ...)
  2022-12-01  9:08 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
@ 2022-12-01 14:49 ` Petri Latvala
  2022-12-01 16:29 ` [igt-dev] [PATCH v2] " Mark Yacoub
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Petri Latvala @ 2022-12-01 14:49 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: robdclark, khaled.almahallawy, vsuley, igt-dev, kalin, seanpaul,
	ihf, matthewtlam, markyacoub, amstan

On Wed, Nov 30, 2022 at 03:45:26PM -0500, Mark Yacoub wrote:
> [Why]
> kms_chamelium tests file has grown so much and became a bit big to
> manage.
> Splitting specific tests like we do for kms_ tests into separate files
> puts logically related functionalities into the same place so tests are
> more clear.
> 
> [How]
> Split kms_chamelium into 4 different tests, each testing something
> specific. The tests are:
> 1. kms_chamelium_audio
> 2. kms_chamelium_edid
> 3. kms_chamelium_frames
> 4. kms_chamelium_hpd
> 5. kms_chamelium_color which used to be kms_color_chamelium but renamed
>    for consistency.
> 
> All common code lives in kms_chamelium_helper and the function names
> have a chamelium_ prefix.
> 
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> ---
>  docs/chamelium.txt                            |    2 +-
>  lib/igt_edid.h                                |    1 +
>  lib/igt_eld.h                                 |    1 +
>  lib/monitor_edids/monitor_edids_helper.c      |    2 +-
>  tests/chamelium/kms_chamelium.c               | 3132 -----------------
>  tests/chamelium/kms_chamelium_audio.c         |  858 +++++
>  ...olor_chamelium.c => kms_chamelium_color.c} |    0
>  tests/chamelium/kms_chamelium_edid.c          |  532 +++
>  tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
>  tests/chamelium/kms_chamelium_helper.c        |  330 ++
>  tests/chamelium/kms_chamelium_helper.h        |   74 +
>  tests/chamelium/kms_chamelium_hpd.c           |  512 +++
>  tests/intel-ci/blacklist.txt                  |    2 +-
>  tests/intel-ci/fast-feedback.testlist         |   18 +-
>  tests/kms_color_helper.h                      |    2 +-
>  tests/meson.build                             |   14 +-
>  tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
>  17 files changed, 3429 insertions(+), 3164 deletions(-)
>  delete mode 100644 tests/chamelium/kms_chamelium.c
>  create mode 100644 tests/chamelium/kms_chamelium_audio.c
>  rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
>  create mode 100644 tests/chamelium/kms_chamelium_edid.c
>  create mode 100644 tests/chamelium/kms_chamelium_frames.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.h
>  create mode 100644 tests/chamelium/kms_chamelium_hpd.c
> 
> diff --git a/docs/chamelium.txt b/docs/chamelium.txt
> index c4c22468..f82c8b0c 100644
> --- a/docs/chamelium.txt
> +++ b/docs/chamelium.txt
> @@ -241,7 +241,7 @@ Current Support in IGT
>  
>  Support for the Chamelium platform in IGT is found in the following places:
>  * lib/igt_chamelium.c: library with Chamelium-related helpers
> -* tests/kms_chamelium.c: sub-tests using the Chamelium
> +* tests/kms_chamelium_*.c: sub-tests using the Chamelium
>  
>  As of early April 2019, the following features are tested by IGT:
>  * Pixel-by-pixel frame integrity tests for DP and HDMI
> diff --git a/lib/igt_edid.h b/lib/igt_edid.h
> index 477f16c2..85a9ef5e 100644
> --- a/lib/igt_edid.h
> +++ b/lib/igt_edid.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdint.h>
> +#include <stddef.h>
>  
>  #include <xf86drmMode.h>
>  
> diff --git a/lib/igt_eld.h b/lib/igt_eld.h
> index 30d7012d..1a46b6d2 100644
> --- a/lib/igt_eld.h
> +++ b/lib/igt_eld.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdbool.h>
> +#include <stddef.h>
>  
>  #include "igt_edid.h"
>  
> diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
> index 41f199bd..1cbf1c22 100644
> --- a/lib/monitor_edids/monitor_edids_helper.c
> +++ b/lib/monitor_edids/monitor_edids_helper.c
> @@ -1,4 +1,4 @@
> -// SPDX-License-Identifier: GPL-2.0
> +// SPDX-License-Identifier: MIT
>  /*
>   * A helper library for parsing and making use of real EDID data from monitors
>   * and make them compatible with IGT and Chamelium.
> diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
> deleted file mode 100644
> index 3c4b4d75..00000000
> --- a/tests/chamelium/kms_chamelium.c
> +++ /dev/null
> @@ -1,3132 +0,0 @@
> -/*
> - * Copyright © 2016 Red Hat Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - * Authors:
> - *    Lyude Paul <lyude@redhat.com>
> - */
> -
> -#include "config.h"
> -#include "igt.h"
> -#include "igt_vc4.h"
> -#include "igt_edid.h"
> -#include "igt_eld.h"
> -#include "igt_infoframe.h"
> -#include "monitor_edids/dp_edids.h"
> -#include "monitor_edids/hdmi_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,
> -	TEST_MODESET_ON_OFF,
> -	TEST_MODESET_OFF,
> -};
> -
> -typedef struct {
> -	struct chamelium *chamelium;
> -	struct chamelium_port **ports;
> -	igt_display_t display;
> -	int port_count;
> -
> -	int drm_fd;
> -
> -	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> -} data_t;
> -
> -#define ONLINE_TIMEOUT 20 /* seconds */
> -
> -#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> -#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> -
> -#define HPD_TOGGLE_COUNT_VGA 5
> -#define HPD_TOGGLE_COUNT_DP_HDMI 15
> -#define HPD_TOGGLE_COUNT_FAST 3
> -
> -static void
> -get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
> -{
> -	drmModeConnector *connector;
> -	uint64_t link_status;
> -	drmModePropertyPtr prop;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		connector = chamelium_port_get_connector(data->chamelium,
> -							 data->ports[p], false);
> -
> -		igt_assert(kmstest_get_property(data->drm_fd,
> -						connector->connector_id,
> -						DRM_MODE_OBJECT_CONNECTOR,
> -						"link-status", NULL,
> -						&link_status, &prop));
> -
> -		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> -
> -		drmModeFreeProperty(prop);
> -		drmModeFreeConnector(connector);
> -	}
> -}
> -
> -/* Wait for hotplug and return the remaining time left from timeout */
> -static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> -{
> -	struct timespec start, end;
> -	int elapsed;
> -	bool detected;
> -
> -	igt_assert_eq(igt_gettime(&start), 0);
> -	detected = igt_hotplug_detected(mon, *timeout);
> -	igt_assert_eq(igt_gettime(&end), 0);
> -
> -	elapsed = igt_time_elapsed(&start, &end);
> -	igt_assert_lte(0, elapsed);
> -	*timeout = max(0, *timeout - elapsed);
> -
> -	return detected;
> -}
> -
> -static void
> -wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
> -				 struct chamelium_port *port,
> -				 drmModeConnection status)
> -{
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int hotplug_count = 0;
> -
> -	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> -			  chamelium_port_get_name(port),
> -			  kmstest_connector_status_str(status));
> -
> -	while (timeout > 0) {
> -		if (!wait_for_hotplug(mon, &timeout))
> -			break;
> -
> -		hotplug_count++;
> -
> -		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> -						port) == status)
> -			return;
> -	}
> -
> -	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> -			    chamelium_port_get_name(port),
> -			    kmstest_connector_status_str(status),
> -			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
> -}
> -
> -
> -static int chamelium_vga_modes[][2] = {
> -	{ 1600, 1200 },
> -	{ 1920, 1200 },
> -	{ 1920, 1080 },
> -	{ 1680, 1050 },
> -	{ 1280, 1024 },
> -	{ 1280, 960 },
> -	{ 1440, 900 },
> -	{ 1280, 800 },
> -	{ 1024, 768 },
> -	{ 1360, 768 },
> -	{ 1280, 720 },
> -	{ 800, 600 },
> -	{ 640, 480 },
> -	{ -1, -1 },
> -};
> -
> -static bool
> -prune_vga_mode(data_t *data, drmModeModeInfo *mode)
> -{
> -	int i = 0;
> -
> -	while (chamelium_vga_modes[i][0] != -1) {
> -		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> -		    mode->vdisplay == chamelium_vga_modes[i][1])
> -			return false;
> -
> -		i++;
> -	}
> -
> -	return true;
> -}
> -
> -static bool
> -check_analog_bridge(data_t *data, struct chamelium_port *port)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -	uint64_t edid_blob_id;
> -	const struct edid *edid;
> -	char edid_vendor[3];
> -
> -	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> -		drmModeFreeConnector(connector);
> -		return false;
> -	}
> -
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	edid = (const struct edid *) edid_blob->data;
> -	edid_get_mfg(edid, edid_vendor);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -
> -	/* Analog bridges provide their own EDID */
> -	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> -	    edid_vendor[2] != 'T')
> -		return true;
> -
> -	return false;
> -}
> -
> -static void chamelium_paint_xr24_pattern(uint32_t *data,
> -					 size_t width, size_t height,
> -					 size_t stride, size_t block_size)
> -{
> -	uint32_t colors[] = { 0xff000000,
> -			      0xffff0000,
> -			      0xff00ff00,
> -			      0xff0000ff,
> -			      0xffffffff };
> -	unsigned i, j;
> -
> -	for (i = 0; i < height; i++)
> -		for (j = 0; j < width; j++)
> -			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
> -}
> -
> -static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
> -				    uint32_t fourcc, size_t block_size,
> -				    struct igt_fb *fb)
> -{
> -	int fb_id;
> -	void *ptr;
> -
> -	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> -
> -	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> -			      DRM_FORMAT_MOD_LINEAR, fb);
> -	igt_assert(fb_id > 0);
> -
> -	ptr = igt_fb_map_buffer(fb->fd, fb);
> -	igt_assert(ptr);
> -
> -	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> -				     block_size);
> -	igt_fb_unmap_buffer(fb, ptr);
> -
> -	return fb_id;
> -}
> -
> -static void
> -enable_output(data_t *data,
> -	      struct chamelium_port *port,
> -	      igt_output_t *output,
> -	      drmModeModeInfo *mode,
> -	      struct igt_fb *fb)
> -{
> -	igt_display_t *display = output->display;
> -	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -
> -	igt_assert(primary);
> -
> -	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> -	igt_plane_set_fb(primary, fb);
> -	igt_output_override_mode(output, mode);
> -
> -	/* Clear any color correction values that might be enabled */
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
> -
> -	igt_display_commit2(display, COMMIT_ATOMIC);
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> -		usleep(250000);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
> -{
> -	enum pipe pipe;
> -
> -	for_each_pipe(display, pipe) {
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			return pipe;
> -		}
> -	}
> -
> -	igt_assert_f(false, "No pipe found for output %s\n",
> -		     igt_output_name(output));
> -}
> -
> -static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
> -{
> -	int fb_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, fb);
> -
> -	igt_assert(fb_id > 0);
> -}
> -
> -static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
> -								   port, false);
> -	drmModeModeInfo mode;
> -	igt_assert(&connector->modes[0] != NULL);
> -	memcpy(&mode, &connector->modes[0], sizeof(mode));
> -	drmModeFreeConnector(connector);
> -	return mode;
> -}
> -
> -static igt_output_t *get_output_for_port(data_t *data,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector =
> -		chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_output_t *output = igt_output_from_connector(&data->display,
> -							 connector);
> -	drmModeFreeConnector(connector);
> -	igt_assert(output != NULL);
> -	return output;
> -}
> -
> -static const char test_hotplug_for_each_pipe_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug for each pipe with valid output";
> -static void
> -test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	enum pipe pipe;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	chamelium_reset_state(&data->display,
> -			      data->chamelium,
> -			      port,
> -			      data->ports,
> -			      data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	/* Disconnect if any port got connected */
> -	chamelium_unplug(data->chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port,
> -			DRM_MODE_DISCONNECTED);
> -
> -	for_each_pipe(&data->display, pipe) {
> -		igt_flush_uevents(mon);
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -		output = get_output_for_port(data, port);
> -
> -		/* If pipe is valid for output then set it */
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			igt_output_set_pipe(output, pipe);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -
> -		chamelium_unplug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_DISCONNECTED);
> -		igt_flush_uevents(mon);
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_basic_hotplug_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug";
> -static void
> -test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
> -	     enum test_modeset_mode modeset_mode)
> -{
> -	int i;
> -	enum pipe pipe;
> -	struct igt_fb fb = {0};
> -	drmModeModeInfo mode;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	igt_output_t *output = get_output_for_port(data, port);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -
> -	for (i = 0; i < toggle_count; i++) {
> -		igt_flush_uevents(mon);
> -
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF ||
> -		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
> -			if (i == 0) {
> -				/* We can only get mode and pipe once we are connected */
> -				output = get_output_for_port(data, port);
> -				pipe = get_pipe_for_output(&data->display, output);
> -				mode = get_mode_for_port(data->chamelium, port);
> -				create_fb_for_mode(data, &fb, &mode);
> -			}
> -
> -			igt_output_set_pipe(output, pipe);
> -			enable_output(data, port, output, &mode, &fb);
> -		}
> -
> -		/* Now check if we get a hotplug from disconnection */
> -		chamelium_unplug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_DISCONNECTED);
> -
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF) {
> -			igt_output_set_pipe(output, PIPE_NONE);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static void set_edid(data_t *data, struct chamelium_port *port,
> -		     enum igt_custom_edid_type edid)
> -{
> -	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> -}
> -
> -static const char igt_custom_edid_type_read_desc[] =
> -	"Make sure the EDID exposed by KMS is the same as the screen's";
> -static void
> -igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector;
> -	size_t raw_edid_size;
> -	const struct edid *raw_edid;
> -	uint64_t edid_blob_id;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_skip_on(check_analog_bridge(data, port));
> -
> -	connector = chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob_id != 0);
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> -	raw_edid_size = edid_get_size(raw_edid);
> -	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void
> -try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -		       enum igt_suspend_state state, enum igt_suspend_test test,
> -		       struct udev_monitor *mon, bool connected)
> -{
> -	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> -						     DRM_MODE_CONNECTED;
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int delay;
> -	int p;
> -
> -	igt_flush_uevents(mon);
> -
> -	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> -
> -	if (port) {
> -		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> -					      !connected);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			port = data->ports[p];
> -			chamelium_schedule_hpd_toggle(data->chamelium, port,
> -						      delay, !connected);
> -		}
> -
> -		port = NULL;
> -	}
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(wait_for_hotplug(mon, &timeout));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	if (port) {
> -		igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -							  data->chamelium,
> -							  port),
> -							  target_state);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			drmModeConnection current_state;
> -
> -			port = data->ports[p];
> -			/*
> -			 * There could be as many hotplug events sent by
> -			 * driver as connectors we scheduled an HPD toggle on
> -			 * above, depending on timing. So if we're not seeing
> -			 * the expected connector state try to wait for an HPD
> -			 * event for each connector/port.
> -			 */
> -			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			if (p > 0 && current_state != target_state) {
> -				igt_assert(wait_for_hotplug(mon, &timeout));
> -				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			}
> -
> -			igt_assert_eq(current_state, target_state);
> -		}
> -
> -		port = NULL;
> -	}
> -}
> -
> -static const char test_suspend_resume_hpd_desc[] =
> -	"Toggle HPD during suspend, check that uevents are sent and connector "
> -	"status is updated";
> -static void
> -test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -			enum igt_suspend_state state,
> -			enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_hpd_common_desc[] =
> -	"Toggle HPD during suspend on all connectors, check that uevents are "
> -	"sent and connector status is updated";
> -static void
> -test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
> -			       enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	struct chamelium_port *port;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		port = data->ports[p];
> -		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_edid_change_desc[] =
> -	"Simulate a screen being unplugged and another screen being plugged "
> -	"during suspend, check that a uevent is sent and connector status is "
> -	"updated";
> -static void
> -test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
> -				enum igt_suspend_state state,
> -				enum igt_suspend_test test,
> -				enum igt_custom_edid_type edid,
> -				enum igt_custom_edid_type alt_edid)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	bool link_status_failed[2][data->port_count];
> -	int p;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Catch the event and flush all remaining ones. */
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_flush_uevents(mon);
> -
> -	/* First plug in the port */
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	/*
> -	 * Change the edid before we suspend. On resume, the machine should
> -	 * notice the EDID change and fire a hotplug event.
> -	 */
> -	set_edid(data, port, alt_edid);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[0]);
> -
> -	igt_flush_uevents(mon);
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[1]);
> -
> -	for (p = 0; p < data->port_count; p++)
> -		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
> -}
> -
> -static igt_output_t *
> -prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	igt_display_t *display = &data->display;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	/* The chamelium's default EDID has a lot of resolutions, way more then
> -	 * we need to test. Additionally the default EDID doesn't support HDMI
> -	 * audio.
> -	 */
> -	set_edid(data, port, edid);
> -
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_display_reset(display);
> -
> -	output = get_output_for_port(data, port);
> -
> -	/* Refresh pipe to update connected status */
> -	igt_output_set_pipe(output, PIPE_NONE);
> -
> -	pipe = get_pipe_for_output(display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	return output;
> -}
> -
> -static void do_test_display(data_t *data, struct chamelium_port *port,
> -			    igt_output_t *output, drmModeModeInfo *mode,
> -			    uint32_t fourcc, enum chamelium_check check,
> -			    int count)
> -{
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	struct igt_fb frame_fb, fb;
> -	int i, fb_id, captured_frame_count;
> -	int frame_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
> -				  DRM_FORMAT_MOD_LINEAR);
> -	igt_assert(frame_id > 0);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&fb);
> -
> -	enable_output(data, port, output, mode, &frame_fb);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		igt_crc_t *expected_crc;
> -		igt_crc_t *crc;
> -
> -		/* We want to keep the display running for a little bit, since
> -		 * there's always the potential the driver isn't able to keep
> -		 * the display running properly for very long
> -		 */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == count);
> -
> -		igt_debug("Captured %d frames\n", captured_frame_count);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		for (i = 0; i < captured_frame_count; i++)
> -			chamelium_assert_crc_eq_or_dump(data->chamelium,
> -							expected_crc, &crc[i],
> -							&fb, i);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> -		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		igt_assert(count == 1);
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG)
> -			chamelium_crop_analog_frame(dump, mode->hdisplay,
> -						    mode->vdisplay);
> -
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	igt_remove_fb(data->drm_fd, &frame_fb);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static const char test_display_one_mode_desc[] =
> -	"Pick the first mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_one_mode(data_t *data, struct chamelium_port *port,
> -				  uint32_t fourcc, enum chamelium_check check,
> -				  int count)
> -{
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
> -
> -	mode = &connector->modes[0];
> -	if (check == CHAMELIUM_CHECK_ANALOG) {
> -		bool bridge = check_analog_bridge(data, port);
> -
> -		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> -	}
> -
> -	do_test_display(data, port, output, mode, fourcc, check, count);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static const char test_display_all_modes_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_all_modes(data_t *data, struct chamelium_port *port,
> -				   uint32_t fourcc, enum chamelium_check check,
> -				   int count)
> -{
> -	bool bridge;
> -	int i, count_modes;
> -
> -	if (check == CHAMELIUM_CHECK_ANALOG)
> -		bridge = check_analog_bridge(data, port);
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -		igt_require(igt_plane_has_format_mod(primary, fourcc,
> -			    DRM_FORMAT_MOD_LINEAR));
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> -		    prune_vga_mode(data, mode))
> -			continue;
> -
> -		do_test_display(data, port, output, mode, fourcc, check,
> -				count);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -static const char test_display_frame_dump_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then download the captured frames and compare them "
> -	"bit-by-bit to the sent ones";
> -static void
> -test_display_frame_dump(data_t *data, struct chamelium_port *port)
> -{
> -
> -	int i, count_modes;
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		struct igt_fb fb;
> -		struct chamelium_frame_dump *frame;
> -		drmModeModeInfo *mode;
> -		drmModeConnector *connector;
> -		int fb_id, j;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		igt_debug("Reading frame dumps from Chamelium...\n");
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> -		for (j = 0; j < 5; j++) {
> -			frame = chamelium_read_captured_frame(data->chamelium,
> -							      j);
> -			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> -			chamelium_destroy_frame_dump(frame);
> -		}
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> -
> -static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> -		       drmModeModeInfo *mode)
> -{
> -	struct chamelium_video_params video_params = {0};
> -	double mode_clock;
> -	int mode_hsync_offset, mode_vsync_offset;
> -	int mode_hsync_width, mode_vsync_width;
> -	int mode_hsync_polarity, mode_vsync_polarity;
> -
> -	chamelium_port_get_video_params(chamelium, port, &video_params);
> -
> -	mode_clock = (double) mode->clock / 1000;
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> -		/* this is what chamelium understands as offsets for DP */
> -		mode_hsync_offset = mode->htotal - mode->hsync_start;
> -		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> -	} else {
> -		/* and this is what they are for other connectors */
> -		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> -		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> -	}
> -
> -	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> -	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> -
> -	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> -	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> -
> -	igt_debug("Checking video mode:\n");
> -	igt_debug("clock: got %f, expected %f ± %f%%\n",
> -		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
> -	igt_debug("hactive: got %d, expected %d\n",
> -		  video_params.hactive, mode->hdisplay);
> -	igt_debug("vactive: got %d, expected %d\n",
> -		  video_params.vactive, mode->vdisplay);
> -	igt_debug("hsync_offset: got %d, expected %d\n",
> -		  video_params.hsync_offset, mode_hsync_offset);
> -	igt_debug("vsync_offset: got %d, expected %d\n",
> -		  video_params.vsync_offset, mode_vsync_offset);
> -	igt_debug("htotal: got %d, expected %d\n",
> -		  video_params.htotal, mode->htotal);
> -	igt_debug("vtotal: got %d, expected %d\n",
> -		  video_params.vtotal, mode->vtotal);
> -	igt_debug("hsync_width: got %d, expected %d\n",
> -		  video_params.hsync_width, mode_hsync_width);
> -	igt_debug("vsync_width: got %d, expected %d\n",
> -		  video_params.vsync_width, mode_vsync_width);
> -	igt_debug("hsync_polarity: got %d, expected %d\n",
> -		  video_params.hsync_polarity, mode_hsync_polarity);
> -	igt_debug("vsync_polarity: got %d, expected %d\n",
> -		  video_params.vsync_polarity, mode_vsync_polarity);
> -
> -	if (!isnan(video_params.clock)) {
> -		igt_assert(video_params.clock >
> -			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> -		igt_assert(video_params.clock <
> -			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> -	}
> -	igt_assert(video_params.hactive == mode->hdisplay);
> -	igt_assert(video_params.vactive == mode->vdisplay);
> -	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> -	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> -	igt_assert(video_params.htotal == mode->htotal);
> -	igt_assert(video_params.vtotal == mode->vtotal);
> -	igt_assert(video_params.hsync_width == mode_hsync_width);
> -	igt_assert(video_params.vsync_width == mode_vsync_width);
> -	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> -	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> -}
> -
> -static const char test_mode_timings_desc[] =
> -	"For each mode of the IGT base EDID, perform a modeset and check the "
> -	"mode detected by the Chamelium receiver matches the mode we set";
> -static void test_mode_timings(data_t *data, struct chamelium_port *port)
> -{
> -	int i, count_modes;
> -
> -	i = 0;
> -	igt_require(chamelium_supports_get_video_params(data->chamelium));
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -		int fb_id;
> -		struct igt_fb fb;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port, false);
> -		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		/* Trigger the FSM */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> -
> -		check_mode(data->chamelium, port, mode);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -struct vic_mode {
> -	int hactive, vactive;
> -	int vrefresh; /* Hz */
> -	uint32_t picture_ar;
> -};
> -
> -/* Maps Video Identification Codes to a mode */
> -static const struct vic_mode vic_modes[] = {
> -	[16] = {
> -		.hactive = 1920,
> -		.vactive = 1080,
> -		.vrefresh = 60,
> -		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> -	},
> -};
> -
> -/* Maps aspect ratios to their mode flag */
> -static const uint32_t mode_ar_flags[] = {
> -	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> -};
> -
> -static enum infoframe_avi_picture_aspect_ratio
> -get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> -{
> -	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> -	switch (aspect_ratio) {
> -	case DRM_MODE_PICTURE_ASPECT_4_3:
> -		return INFOFRAME_AVI_PIC_AR_4_3;
> -	case DRM_MODE_PICTURE_ASPECT_16_9:
> -		return INFOFRAME_AVI_PIC_AR_16_9;
> -	default:
> -		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> -	}
> -}
> -
> -static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> -				 drmModeModeInfo *drm_mode)
> -{
> -	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> -
> -	return vic_mode->hactive == drm_mode->hdisplay &&
> -	       vic_mode->vactive == drm_mode->vdisplay &&
> -	       vic_mode->vrefresh == drm_mode->vrefresh &&
> -	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> -}
> -
> -static const char test_display_aspect_ratio_desc[] =
> -	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> -	"check they include the relevant fields";
> -static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	int fb_id, i;
> -	struct igt_fb fb;
> -	bool found, ok;
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_avi infoframe_avi;
> -	uint8_t vic = 16; /* TODO: test more VICs */
> -	const struct vic_mode *vic_mode;
> -	uint32_t aspect_ratio;
> -	enum infoframe_avi_picture_aspect_ratio frame_ar;
> -
> -	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	vic_mode = &vic_modes[vic];
> -	aspect_ratio = vic_mode->picture_ar;
> -
> -	found = false;
> -	igt_assert(connector->count_modes > 0);
> -	for (i = 0; i < connector->count_modes; i++) {
> -		mode = &connector->modes[i];
> -
> -		if (vic_mode_matches_drm(vic_mode, mode)) {
> -			found = true;
> -			break;
> -		}
> -	}
> -	igt_assert_f(found,
> -		     "Failed to find mode with the correct aspect ratio\n");
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> -						 CHAMELIUM_INFOFRAME_AVI);
> -	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> -
> -	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> -				 infoframe->payload, infoframe->payload_size);
> -	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> -
> -	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> -
> -	igt_debug("Checking AVI InfoFrame\n");
> -	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> -		  infoframe_avi.picture_aspect_ratio, frame_ar);
> -	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> -		  infoframe_avi.vic, vic);
> -
> -	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> -	igt_assert(infoframe_avi.vic == vic);
> -
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_remove_fb(data->drm_fd, &fb);
> -	drmModeFreeConnector(connector);
> -}
> -
> -
> -/* Playback parameters control the audio signal we synthesize and send */
> -#define PLAYBACK_CHANNELS 2
> -#define PLAYBACK_SAMPLES 1024
> -
> -/* Capture paremeters control the audio signal we receive */
> -#define CAPTURE_SAMPLES 2048
> -
> -#define AUDIO_TIMEOUT 2000 /* ms */
> -/* A streak of 3 gives confidence that the signal is good. */
> -#define MIN_STREAK 3
> -
> -#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> -#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> -#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> -
> -/* TODO: enable >48KHz rates, these are not reliable */
> -static int test_sampling_rates[] = {
> -	32000,
> -	44100,
> -	48000,
> -	/* 88200, */
> -	/* 96000, */
> -	/* 176400, */
> -	/* 192000, */
> -};
> -
> -static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
> -
> -/* Test frequencies (Hz): a sine signal will be generated for each.
> - *
> - * Depending on the sampling rate chosen, it might not be possible to properly
> - * detect the generated sine (see Nyquist–Shannon sampling theorem).
> - * Frequencies that can't be reliably detected will be automatically pruned in
> - * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> - * tested with a 192KHz sampling rate.
> - */
> -static int test_frequencies[] = {
> -	300,
> -	600,
> -	1200,
> -	10000,
> -	80000,
> -};
> -
> -static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> -
> -static const snd_pcm_format_t test_formats[] = {
> -	SND_PCM_FORMAT_S16_LE,
> -	SND_PCM_FORMAT_S24_LE,
> -	SND_PCM_FORMAT_S32_LE,
> -};
> -
> -static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
> -
> -struct audio_state {
> -	struct alsa *alsa;
> -	struct chamelium *chamelium;
> -	struct chamelium_port *port;
> -	struct chamelium_stream *stream;
> -
> -	/* The capture format is only available after capture has started. */
> -	struct {
> -		snd_pcm_format_t format;
> -		int channels;
> -		int rate;
> -	} playback, capture;
> -
> -	char *name;
> -	struct audio_signal *signal; /* for frequencies test only */
> -	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	size_t recv_pages;
> -	int msec;
> -
> -	int dump_fd;
> -	char *dump_path;
> -
> -	pthread_t thread;
> -	atomic_bool run;
> -	atomic_bool positive; /* for pulse test only */
> -};
> -
> -static void audio_state_init(struct audio_state *state, data_t *data,
> -			     struct alsa *alsa, struct chamelium_port *port,
> -			     snd_pcm_format_t format, int channels, int rate)
> -{
> -	memset(state, 0, sizeof(*state));
> -	state->dump_fd = -1;
> -
> -	state->alsa = alsa;
> -	state->chamelium = data->chamelium;
> -	state->port = port;
> -
> -	state->playback.format = format;
> -	state->playback.channels = channels;
> -	state->playback.rate = rate;
> -
> -	alsa_configure_output(alsa, format, channels, rate);
> -
> -	state->stream = chamelium_stream_init();
> -	igt_assert_f(state->stream,
> -		     "Failed to initialize Chamelium stream client\n");
> -}
> -
> -static void audio_state_fini(struct audio_state *state)
> -{
> -	chamelium_stream_deinit(state->stream);
> -	free(state->name);
> -}
> -
> -static void *run_audio_thread(void *data)
> -{
> -	struct alsa *alsa = data;
> -
> -	alsa_run(alsa, -1);
> -	return NULL;
> -}
> -
> -static void audio_state_start(struct audio_state *state, const char *name)
> -{
> -	int ret;
> -	bool ok;
> -	size_t i, j;
> -	enum chamelium_stream_realtime_mode stream_mode;
> -	char dump_suffix[64];
> -
> -	free(state->name);
> -	state->name = strdup(name);
> -	state->recv_pages = 0;
> -	state->msec = 0;
> -
> -	igt_debug("Starting %s test with playback format %s, "
> -		  "sampling rate %d Hz and %d channels\n",
> -		  name, snd_pcm_format_name(state->playback.format),
> -		  state->playback.rate, state->playback.channels);
> -
> -	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> -
> -	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> -	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> -	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> -
> -	/* Start playing audio */
> -	state->run = true;
> -	ret = pthread_create(&state->thread, NULL,
> -			     run_audio_thread, state->alsa);
> -	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> -
> -	/* The Chamelium device only supports this PCM format. */
> -	state->capture.format = SND_PCM_FORMAT_S32_LE;
> -
> -	/* Only after we've started playing audio, we can retrieve the capture
> -	 * format used by the Chamelium device. */
> -	chamelium_get_audio_format(state->chamelium, state->port,
> -				   &state->capture.rate,
> -				   &state->capture.channels);
> -	if (state->capture.rate == 0) {
> -		igt_debug("Audio receiver doesn't indicate the capture "
> -			 "sampling rate, assuming it's %d Hz\n",
> -			 state->playback.rate);
> -		state->capture.rate = state->playback.rate;
> -	}
> -
> -	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> -					    state->channel_mapping);
> -	/* Make sure we can capture all channels we send. */
> -	for (i = 0; i < state->playback.channels; i++) {
> -		ok = false;
> -		for (j = 0; j < state->capture.channels; j++) {
> -			if (state->channel_mapping[j] == i) {
> -				ok = true;
> -				break;
> -			}
> -		}
> -		igt_assert_f(ok, "Cannot capture all channels\n");
> -	}
> -
> -	if (igt_frame_dump_is_enabled()) {
> -		snprintf(dump_suffix, sizeof(dump_suffix),
> -			 "capture-%s-%s-%dch-%dHz",
> -			 name, snd_pcm_format_name(state->playback.format),
> -			 state->playback.channels, state->playback.rate);
> -
> -		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> -							      state->capture.rate,
> -							      state->capture.channels,
> -							      &state->dump_path);
> -		igt_assert_f(state->dump_fd >= 0,
> -			     "Failed to create audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_receive(struct audio_state *state,
> -				int32_t **recv, size_t *recv_len)
> -{
> -	bool ok;
> -	size_t page_count;
> -	size_t recv_size;
> -
> -	ok = chamelium_stream_receive_realtime_audio(state->stream,
> -						     &page_count,
> -						     recv, recv_len);
> -	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> -
> -	state->msec = state->recv_pages * *recv_len
> -		      / (double) state->capture.channels
> -		      / (double) state->capture.rate * 1000;
> -	state->recv_pages++;
> -
> -	if (state->dump_fd >= 0) {
> -		recv_size = *recv_len * sizeof(int32_t);
> -		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
> -			     "Failed to write to audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_stop(struct audio_state *state, bool success)
> -{
> -	bool ok;
> -	int ret;
> -	struct chamelium_audio_file *audio_file;
> -	enum igt_log_level log_level;
> -
> -	igt_debug("Stopping audio playback\n");
> -	state->run = false;
> -	ret = pthread_join(state->thread, NULL);
> -	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> -
> -	ok = chamelium_stream_stop_realtime_audio(state->stream);
> -	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> -
> -	audio_file = chamelium_stop_capturing_audio(state->chamelium,
> -						    state->port);
> -	if (audio_file) {
> -		igt_debug("Audio file saved on the Chamelium in %s\n",
> -			  audio_file->path);
> -		chamelium_destroy_audio_file(audio_file);
> -	}
> -
> -	if (state->dump_fd >= 0) {
> -		close(state->dump_fd);
> -		state->dump_fd = -1;
> -
> -		if (success) {
> -			/* Test succeeded, no need to keep the captured data */
> -			unlink(state->dump_path);
> -		} else
> -			igt_debug("Saved captured audio data to %s\n",
> -				  state->dump_path);
> -		free(state->dump_path);
> -		state->dump_path = NULL;
> -	}
> -
> -	if (success)
> -		log_level = IGT_LOG_DEBUG;
> -	else
> -		log_level = IGT_LOG_CRITICAL;
> -
> -	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
> -		"sampling rate %d Hz and %d channels: %s\n",
> -		state->name, snd_pcm_format_name(state->playback.format),
> -		state->playback.rate, state->playback.channels,
> -		success ? "ALL GREEN" : "FAILED");
> -
> -}
> -
> -static void check_audio_infoframe(struct audio_state *state)
> -{
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_audio infoframe_audio;
> -	struct infoframe_audio expected = {0};
> -	bool ok;
> -
> -	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "Chamelium board doesn't support GetLastInfoFrame\n");
> -		return;
> -	}
> -
> -	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> -	expected.channel_count = state->playback.channels;
> -	expected.sampling_freq = state->playback.rate;
> -	expected.sample_size = snd_pcm_format_width(state->playback.format);
> -
> -	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> -						 CHAMELIUM_INFOFRAME_AUDIO);
> -	if (infoframe == NULL && state->playback.channels <= 2) {
> -		/* Audio InfoFrames are optional for mono and stereo audio */
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "no InfoFrame received\n");
> -		return;
> -	}
> -	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> -
> -	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> -				   infoframe->payload, infoframe->payload_size);
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> -
> -	igt_debug("Checking audio InfoFrame:\n");
> -	igt_debug("coding_type: got %d, expected %d\n",
> -		  infoframe_audio.coding_type, expected.coding_type);
> -	igt_debug("channel_count: got %d, expected %d\n",
> -		  infoframe_audio.channel_count, expected.channel_count);
> -	igt_debug("sampling_freq: got %d, expected %d\n",
> -		  infoframe_audio.sampling_freq, expected.sampling_freq);
> -	igt_debug("sample_size: got %d, expected %d\n",
> -		  infoframe_audio.sample_size, expected.sample_size);
> -
> -	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> -		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> -	if (infoframe_audio.channel_count >= 0)
> -		igt_assert(infoframe_audio.channel_count == expected.channel_count);
> -	if (infoframe_audio.sampling_freq >= 0)
> -		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
> -	if (infoframe_audio.sample_size >= 0)
> -		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> -}
> -
> -static int
> -audio_output_frequencies_callback(void *data, void *buffer, int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	audio_signal_fill(state->signal, tmp, samples);
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool test_audio_frequencies(struct audio_state *state)
> -{
> -	int freq, step;
> -	int32_t *recv, *buf;
> -	double *channel;
> -	size_t i, j, streak;
> -	size_t recv_len, buf_len, buf_cap, channel_len;
> -	bool success;
> -	int capture_chan;
> -
> -	state->signal = audio_signal_init(state->playback.channels,
> -					  state->playback.rate);
> -	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> -
> -	/* We'll choose different frequencies per channel to make sure they are
> -	 * independent from each other. To do so, we'll add a different offset
> -	 * to the base frequencies for each channel. We need to choose a big
> -	 * enough offset so that we're sure to detect mixed up channels. We
> -	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> -	 * difference.
> -	 *
> -	 * Note that we assume capture_rate == playback_rate. We'll assert this
> -	 * later on. We cannot retrieve the capture rate before starting
> -	 * playing audio, so we don't really have the choice.
> -	 */
> -	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> -	for (i = 0; i < test_frequencies_count; i++) {
> -		for (j = 0; j < state->playback.channels; j++) {
> -			freq = test_frequencies[i] + j * step;
> -			audio_signal_add_frequency(state->signal, freq, j);
> -		}
> -	}
> -	audio_signal_synthesize(state->signal);
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_frequencies_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	audio_state_start(state, "frequencies");
> -
> -	igt_assert_f(state->capture.rate == state->playback.rate,
> -		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> -		     state->capture.rate, state->playback.rate);
> -
> -	/* Needs to be a multiple of 128, because that's the number of samples
> -	 * we get per channel each time we receive an audio page from the
> -	 * Chamelium device.
> -	 *
> -	 * Additionally, this value needs to be high enough to guarantee we
> -	 * capture a full period of each sine we generate. If we capture 2048
> -	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> -	 * sines. For lower sampling rates, the capture duration will be
> -	 * longer.
> -	 */
> -	channel_len = CAPTURE_SAMPLES;
> -	channel = malloc(sizeof(double) * channel_len);
> -
> -	buf_cap = state->capture.channels * channel_len;
> -	buf = malloc(sizeof(int32_t) * buf_cap);
> -	buf_len = 0;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -
> -	success = false;
> -	streak = 0;
> -	while (!success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> -		buf_len += recv_len;
> -
> -		if (buf_len < buf_cap)
> -			continue;
> -		igt_assert(buf_len == buf_cap);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (j = 0; j < state->playback.channels; j++) {
> -			capture_chan = state->channel_mapping[j];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", j, capture_chan);
> -
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     buf, buf_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			if (audio_signal_detect(state->signal,
> -						state->capture.rate, j,
> -						channel, channel_len))
> -				streak++;
> -			else
> -				streak = 0;
> -		}
> -
> -		buf_len = 0;
> -
> -		success = streak == MIN_STREAK * state->playback.channels;
> -	}
> -
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -	free(buf);
> -	free(channel);
> -	audio_signal_fini(state->signal);
> -
> -	check_audio_infoframe(state);
> -
> -	return success;
> -}
> -
> -static int audio_output_flatline_callback(void *data, void *buffer,
> -					     int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len, i;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	for (i = 0; i < len; i++)
> -		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> -{
> -	double expected, min, max;
> -	size_t i;
> -	bool ok;
> -
> -	min = max = NAN;
> -	for (i = 0; i < buf_len; i++) {
> -		if (isnan(min) || buf[i] < min)
> -			min = buf[i];
> -		if (isnan(max) || buf[i] > max)
> -			max = buf[i];
> -	}
> -
> -	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> -	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> -	if (ok)
> -		igt_debug("Flatline wave amplitude detected\n");
> -	else
> -		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> -			  min, max);
> -	return ok;
> -}
> -
> -static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> -{
> -	size_t i;
> -
> -	for (i = 0; i < buf_len; i++) {
> -		if (buf[i] < 0)
> -			return i;
> -	}
> -
> -	return -1;
> -}
> -
> -/** test_audio_flatline:
> - *
> - * Send a constant value (one positive, then a negative one) and check that:
> - *
> - * - The amplitude of the flatline is correct
> - * - All channels switch from a positive signal to a negative one at the same
> - *   time (ie. all channels are aligned)
> - */
> -static bool test_audio_flatline(struct audio_state *state)
> -{
> -	bool success, amp_success, align_success;
> -	int32_t *recv;
> -	size_t recv_len, i, channel_len;
> -	ssize_t j;
> -	int streak, capture_chan;
> -	double *channel;
> -	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_flatline_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	/* Start by sending a positive signal */
> -	state->positive = true;
> -
> -	audio_state_start(state, "flatline");
> -
> -	for (i = 0; i < state->playback.channels; i++)
> -		falling_edges[i] = -1;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -	amp_success = false;
> -	streak = 0;
> -	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (i = 0; i < state->playback.channels; i++) {
> -			capture_chan = state->channel_mapping[i];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", i, capture_chan);
> -
> -			channel_len = audio_extract_channel_s32_le(NULL, 0,
> -								   recv, recv_len,
> -								   state->capture.channels,
> -								   capture_chan);
> -			channel = malloc(channel_len * sizeof(double));
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     recv, recv_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			/* Check whether the amplitude is fine */
> -			if (detect_flatline_amplitude(channel, channel_len,
> -						      state->positive))
> -				streak++;
> -			else
> -				streak = 0;
> -
> -			/* If we're now sending a negative signal, detect the
> -			 * falling edge */
> -			j = detect_falling_edge(channel, channel_len);
> -			if (!state->positive && j >= 0) {
> -				falling_edges[i] = recv_len * state->recv_pages
> -						   + j;
> -			}
> -
> -			free(channel);
> -		}
> -
> -		amp_success = streak == MIN_STREAK * state->playback.channels;
> -
> -		if (amp_success && state->positive) {
> -			/* Switch to a negative signal after we've detected the
> -			 * positive one. */
> -			state->positive = false;
> -			amp_success = false;
> -			streak = 0;
> -			igt_debug("Switching to negative square wave\n");
> -		}
> -	}
> -
> -	/* Check alignment between all channels by comparing the index of the
> -	 * falling edge. */
> -	align_success = true;
> -	for (i = 0; i < state->playback.channels; i++) {
> -		if (falling_edges[i] < 0) {
> -			igt_critical("Falling edge not detected for channel %zu\n",
> -				     i);
> -			align_success = false;
> -			continue;
> -		}
> -
> -		if (abs(falling_edges[0] - falling_edges[i]) >
> -		    FLATLINE_ALIGN_ACCURACY) {
> -			igt_critical("Channel alignment mismatch: "
> -				     "channel 0 has a falling edge at index %d "
> -				     "while channel %zu has index %d\n",
> -				     falling_edges[0], i, falling_edges[i]);
> -			align_success = false;
> -		}
> -	}
> -
> -	success = amp_success && align_success;
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -
> -	return success;
> -}
> -
> -static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
> -				      int channels, int sampling_rate)
> -{
> -	if (!alsa_test_output_configuration(alsa, format, channels,
> -					    sampling_rate)) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because at least one of the "
> -			  "selected output devices doesn't support this "
> -			  "configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	/* TODO: the Chamelium device sends a malformed signal for some audio
> -	 * configurations. See crbug.com/950917 */
> -	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> -			channels > 2) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because the Chamelium device "
> -			  "doesn't support this configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	return true;
> -}
> -
> -static const char test_display_audio_desc[] =
> -	"Playback various audio signals with various audio formats/rates, "
> -	"capture them and check they are correct";
> -static void
> -test_display_audio(data_t *data, struct chamelium_port *port,
> -		   const char *audio_device, enum igt_custom_edid_type edid)
> -{
> -	bool run, success;
> -	struct alsa *alsa;
> -	int ret;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id, i, j;
> -	int channels, sampling_rate;
> -	snd_pcm_format_t format;
> -	struct audio_state state;
> -
> -	igt_require(alsa_has_exclusive_access());
> -
> -	/* Old Chamelium devices need an update for DisplayPort audio and
> -	 * chamelium_get_audio_format support. */
> -	igt_require(chamelium_has_audio_support(data->chamelium, port));
> -
> -	alsa = alsa_init();
> -	igt_assert(alsa);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because the receiver won't try to receive audio if
> -	 * it doesn't receive video. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	run = false;
> -	success = true;
> -	for (i = 0; i < test_sampling_rates_count; i++) {
> -		for (j = 0; j < test_formats_count; j++) {
> -			ret = alsa_open_output(alsa, audio_device);
> -			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> -
> -			/* TODO: playback on all 8 available channels (this
> -			 * isn't supported by Chamelium devices yet, see
> -			 * https://crbug.com/950917) */
> -			format = test_formats[j];
> -			channels = PLAYBACK_CHANNELS;
> -			sampling_rate = test_sampling_rates[i];
> -
> -			if (!check_audio_configuration(alsa, format, channels,
> -						       sampling_rate))
> -				continue;
> -
> -			run = true;
> -
> -			audio_state_init(&state, data, alsa, port,
> -					 format, channels, sampling_rate);
> -			success &= test_audio_frequencies(&state);
> -			success &= test_audio_flatline(&state);
> -			audio_state_fini(&state);
> -
> -			alsa_close_output(alsa);
> -		}
> -	}
> -
> -	/* Make sure we tested at least one frequency and format. */
> -	igt_assert(run);
> -	/* Make sure all runs were successful. */
> -	igt_assert(success);
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -
> -	free(alsa);
> -}
> -
> -static const char test_display_audio_edid_desc[] =
> -	"Plug a connector with an EDID suitable for audio, check ALSA's "
> -	"EDID-Like Data reports the correct audio parameters";
> -static void
> -test_display_audio_edid(data_t *data, struct chamelium_port *port,
> -			enum igt_custom_edid_type edid)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id;
> -	struct eld_entry eld;
> -	struct eld_sad *sad;
> -
> -	igt_require(eld_is_supported());
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because audio cannot be played on inactive
> -	 * connectors. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	igt_assert(eld_get_igt(&eld));
> -	igt_assert(eld.sads_len == 1);
> -
> -	sad = &eld.sads[0];
> -	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> -	igt_assert(sad->channels == 2);
> -	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
> -		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
> -	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
> -		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void randomize_plane_stride(data_t *data,
> -				   uint32_t width, uint32_t height,
> -				   uint32_t format, uint64_t modifier,
> -				   size_t *stride)
> -{
> -	size_t stride_min;
> -	uint32_t max_tile_w = 4, tile_w, tile_h;
> -	int i;
> -	struct igt_fb dummy;
> -
> -	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> -
> -	/* Randomize the stride to less than twice the minimum. */
> -	*stride = (rand() % stride_min) + stride_min;
> -
> -	/*
> -	 * Create a dummy FB to determine bpp for each plane, and calculate
> -	 * the maximum tile width from that.
> -	 */
> -	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> -	for (i = 0; i < dummy.num_planes; i++) {
> -		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
> -
> -		if (tile_w > max_tile_w)
> -			max_tile_w = tile_w;
> -	}
> -	igt_remove_fb(data->drm_fd, &dummy);
> -
> -	/*
> -	 * Pixman requires the stride to be aligned to 32-bits, which is
> -	 * reflected in the initial value of max_tile_w and the hw
> -	 * may require a multiple of tile width, choose biggest of the 2.
> -	 */
> -	*stride = ALIGN(*stride, max_tile_w);
> -}
> -
> -static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> -				  uint32_t height, uint32_t format,
> -				  uint64_t *modifier)
> -{
> -	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> -		/* Randomize the column height to less than twice the minimum. */
> -		size_t column_height = (rand() % height) + height;
> -
> -		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
> -			  column_height);
> -
> -		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
> -	}
> -}
> -
> -static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
> -				  drmModeModeInfo *mode,
> -				  uint32_t *width, uint32_t *height,
> -				  uint32_t *format, uint64_t *modifier,
> -				  bool allow_yuv)
> -{
> -	int min_dim;
> -	uint32_t idx[plane->format_mod_count];
> -	unsigned int count = 0;
> -	unsigned int i;
> -
> -	/* First pass to count the supported formats. */
> -	for (i = 0; i < plane->format_mod_count; i++)
> -		if (igt_fb_supported_format(plane->formats[i]) &&
> -		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> -			idx[count++] = i;
> -
> -	igt_assert(count > 0);
> -
> -	i = idx[rand() % count];
> -	*format = plane->formats[i];
> -	*modifier = plane->modifiers[i];
> -
> -	update_tiled_modifier(plane, *width, *height, *format, modifier);
> -
> -	/*
> -	 * Randomize width and height in the mode dimensions range.
> -	 *
> -	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> -	 * least min_dim, because src_w = width - (rand % w / 2).
> -	 *
> -	 * Use a minimum dimension of 16 for YUV, because planar YUV
> -	 * subsamples the UV plane.
> -	 */
> -	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> -
> -	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> -	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> -}
> -
> -static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> -			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> -			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> -			    struct igt_fb *fb)
> -{
> -	igt_plane_set_fb(plane, fb);
> -
> -	igt_plane_set_position(plane, crtc_x, crtc_y);
> -	igt_plane_set_size(plane, crtc_w, crtc_h);
> -
> -	igt_fb_set_position(fb, plane, src_x, src_y);
> -	igt_fb_set_size(fb, plane, src_w, src_h);
> -}
> -
> -static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
> -					drmModeModeInfo *mode,
> -					struct igt_fb *fb,
> -					uint32_t *src_w, uint32_t *src_h,
> -					uint32_t *src_x, uint32_t *src_y,
> -					uint32_t *crtc_w, uint32_t *crtc_h,
> -					int32_t *crtc_x, int32_t *crtc_y,
> -					bool allow_scaling)
> -{
> -	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> -	uint32_t width = fb->width, height = fb->height;
> -	double ratio;
> -	int ret;
> -
> -	/* Randomize source offset in the first half of the original size. */
> -	*src_x = rand() % (width / 2);
> -	*src_y = rand() % (height / 2);
> -
> -	/* The source size only includes the active source area. */
> -	*src_w = width - *src_x;
> -	*src_h = height - *src_y;
> -
> -	if (allow_scaling) {
> -		*crtc_w = (rand() % mode->hdisplay) + 1;
> -		*crtc_h = (rand() % mode->vdisplay) + 1;
> -
> -		/*
> -		 * Don't bother with scaling if dimensions are quite close in
> -		 * order to get non-scaling cases more frequently. Also limit
> -		 * scaling to 3x to avoid agressive filtering that makes
> -		 * comparison less reliable, and don't go above 2x downsampling
> -		 * to avoid possible hw limitations.
> -		 */
> -
> -		ratio = ((double) *crtc_w / *src_w);
> -		if (ratio < 0.5)
> -			*src_w = *crtc_w * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_w = *src_w;
> -		else if (ratio > 3.0)
> -			*crtc_w = *src_w * 3;
> -
> -		ratio = ((double) *crtc_h / *src_h);
> -		if (ratio < 0.5)
> -			*src_h = *crtc_h * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_h = *src_h;
> -		else if (ratio > 3.0)
> -			*crtc_h = *src_h * 3;
> -	} else {
> -		*crtc_w = *src_w;
> -		*crtc_h = *src_h;
> -	}
> -
> -	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> -		/*
> -		 * When scaling is involved, make sure to not go off-bounds or
> -		 * scaled clipping may result in decimal dimensions, that most
> -		 * drivers don't support.
> -		 */
> -		if (*crtc_w < mode->hdisplay)
> -			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> -		else
> -			*crtc_x = 0;
> -
> -		if (*crtc_h < mode->vdisplay)
> -			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> -		else
> -			*crtc_y = 0;
> -	} else {
> -		/*
> -		 * Randomize the on-crtc position and allow the plane to go
> -		 * off-display by less than half of its on-crtc dimensions.
> -		 */
> -		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> -		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> -	}
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
> -			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
> -	ret = igt_display_try_commit_atomic(&data->display,
> -					    DRM_MODE_ATOMIC_TEST_ONLY |
> -					    DRM_MODE_ATOMIC_ALLOW_MODESET,
> -					    NULL);
> -	if (!ret)
> -		return;
> -
> -	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
> -	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
> -
> -	/* Make YUV coordinates a multiple of 2 and retry the math. */
> -	if (is_yuv) {
> -		*src_x &= ~1;
> -		*src_y &= ~1;
> -		*src_w &= ~1;
> -		*src_h &= ~1;
> -		/* To handle 1:1 scaling, clear crtc_w/h too. */
> -		*crtc_w &= ~1;
> -		*crtc_h &= ~1;
> -
> -		if (*crtc_x < 0 && (*crtc_x & 1))
> -			(*crtc_x)++;
> -		else
> -			*crtc_x &= ~1;
> -
> -		/* If negative, round up to 0 instead of down */
> -		if (*crtc_y < 0 && (*crtc_y & 1))
> -			(*crtc_y)++;
> -		else
> -			*crtc_y &= ~1;
> -
> -		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -				*crtc_h, *crtc_x, *crtc_y, fb);
> -		ret = igt_display_try_commit_atomic(&data->display,
> -						DRM_MODE_ATOMIC_TEST_ONLY |
> -						DRM_MODE_ATOMIC_ALLOW_MODESET,
> -						NULL);
> -		if (!ret)
> -			return;
> -	}
> -
> -	igt_assert(!ret || allow_scaling);
> -	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> -		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
> -
> -	*crtc_w = *src_w;
> -	*crtc_h = *src_h;
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -			*crtc_h, *crtc_x, *crtc_y, fb);
> -	igt_display_commit_atomic(&data->display,
> -				  DRM_MODE_ATOMIC_TEST_ONLY |
> -				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> -}
> -
> -static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
> -			     uint32_t src_w, uint32_t src_h,
> -			     uint32_t src_x, uint32_t src_y,
> -			     uint32_t crtc_w, uint32_t crtc_h,
> -			     int32_t crtc_x, int32_t crtc_y,
> -			     struct igt_fb *fb)
> -{
> -	cairo_surface_t *surface;
> -	cairo_surface_t *clipped_surface;
> -	cairo_t *cr;
> -
> -	surface = igt_get_cairo_surface(data->drm_fd, fb);
> -
> -	if (src_x || src_y) {
> -		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> -							     src_w, src_h);
> -
> -		cr = cairo_create(clipped_surface);
> -
> -		cairo_translate(cr, -1. * src_x, -1. * src_y);
> -
> -		cairo_set_source_surface(cr, surface, 0, 0);
> -
> -		cairo_paint(cr);
> -		cairo_surface_flush(clipped_surface);
> -
> -		cairo_destroy(cr);
> -	} else {
> -		clipped_surface = surface;
> -	}
> -
> -	cr = cairo_create(result);
> -
> -	cairo_translate(cr, crtc_x, crtc_y);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_scale(cr, (double) crtc_w / src_w,
> -			    (double) crtc_h / src_h);
> -	}
> -
> -	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> -	cairo_surface_destroy(clipped_surface);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_pattern_set_filter(cairo_get_source(cr),
> -					 CAIRO_FILTER_BILINEAR);
> -		cairo_pattern_set_extend(cairo_get_source(cr),
> -					 CAIRO_EXTEND_NONE);
> -	}
> -
> -	cairo_paint(cr);
> -	cairo_surface_flush(result);
> -
> -	cairo_destroy(cr);
> -}
> -
> -static void prepare_randomized_plane(data_t *data,
> -				     drmModeModeInfo *mode,
> -				     igt_plane_t *plane,
> -				     struct igt_fb *overlay_fb,
> -				     unsigned int index,
> -				     cairo_surface_t *result_surface,
> -				     bool allow_scaling, bool allow_yuv)
> -{
> -	struct igt_fb pattern_fb;
> -	uint32_t overlay_fb_w, overlay_fb_h;
> -	uint32_t overlay_src_w, overlay_src_h;
> -	uint32_t overlay_src_x, overlay_src_y;
> -	int32_t overlay_crtc_x, overlay_crtc_y;
> -	uint32_t overlay_crtc_w, overlay_crtc_h;
> -	uint32_t format;
> -	uint64_t modifier;
> -	size_t stride;
> -	bool tiled;
> -	int fb_id;
> -
> -	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> -			      &format, &modifier, allow_yuv);
> -
> -	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> -	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
> -		  index, overlay_fb_w, overlay_fb_h,
> -		  igt_format_str(format), tiled ? "tiled" : "linear");
> -
> -	/* Get a pattern framebuffer for the overlay plane. */
> -	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> -					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
> -			       format, modifier, &stride);
> -
> -	igt_debug("Plane %d: stride %ld\n", index, stride);
> -
> -	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> -					   modifier, stride);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> -				    &overlay_src_w, &overlay_src_h,
> -				    &overlay_src_x, &overlay_src_y,
> -				    &overlay_crtc_w, &overlay_crtc_h,
> -				    &overlay_crtc_x, &overlay_crtc_y,
> -				    allow_scaling);
> -
> -	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
> -		  overlay_src_w, overlay_src_h);
> -	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> -		  overlay_src_x, overlay_src_y);
> -	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
> -		  overlay_crtc_w, overlay_crtc_h);
> -	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
> -		  overlay_crtc_x, overlay_crtc_y);
> -
> -	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> -			 overlay_src_x, overlay_src_y,
> -			 overlay_crtc_w, overlay_crtc_h,
> -			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
> -
> -	/* Remove the original pattern framebuffer. */
> -	igt_remove_fb(data->drm_fd, &pattern_fb);
> -}
> -
> -static const char test_display_planes_random_desc[] =
> -	"Setup a few overlay planes with random parameters, capture the frame "
> -	"and check it matches the expected output";
> -static void test_display_planes_random(data_t *data,
> -				       struct chamelium_port *port,
> -				       enum chamelium_check check)
> -{
> -	igt_output_t *output;
> -	drmModeModeInfo *mode;
> -	igt_plane_t *primary_plane;
> -	struct igt_fb primary_fb;
> -	struct igt_fb result_fb;
> -	struct igt_fb *overlay_fbs;
> -	igt_crc_t *crc;
> -	igt_crc_t *expected_crc;
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	unsigned int overlay_planes_max = 0;
> -	unsigned int overlay_planes_count;
> -	cairo_surface_t *result_surface;
> -	int captured_frame_count;
> -	bool allow_scaling;
> -	bool allow_yuv;
> -	unsigned int i;
> -	unsigned int fb_id;
> -
> -	switch (check) {
> -	case CHAMELIUM_CHECK_CRC:
> -		allow_scaling = false;
> -		allow_yuv = false;
> -		break;
> -	case CHAMELIUM_CHECK_CHECKERBOARD:
> -		allow_scaling = true;
> -		allow_yuv = true;
> -		break;
> -	default:
> -		igt_assert(false);
> -	}
> -
> -	srand(time(NULL));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Find the connector and pipe. */
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -
> -	mode = igt_output_get_mode(output);
> -
> -	/* Get a framebuffer for the primary plane. */
> -	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary_plane);
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> -	igt_assert(fb_id > 0);
> -
> -	/* Get a framebuffer for the cairo composition result. */
> -	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
> -			      mode->vdisplay, DRM_FORMAT_XRGB8888,
> -			      DRM_FORMAT_MOD_LINEAR, &result_fb);
> -	igt_assert(fb_id > 0);
> -
> -	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> -
> -	/* Paint the primary framebuffer on the result surface. */
> -	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> -			 &primary_fb);
> -
> -	/* Configure the primary plane. */
> -	igt_plane_set_fb(primary_plane, &primary_fb);
> -
> -	overlay_planes_max =
> -		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> -
> -	/* Limit the number of planes to a reasonable scene. */
> -	overlay_planes_max = min(overlay_planes_max, 4u);
> -
> -	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> -	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> -
> -	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> -
> -	for (i = 0; i < overlay_planes_count; i++) {
> -		struct igt_fb *overlay_fb = &overlay_fbs[i];
> -		igt_plane_t *plane =
> -			igt_output_get_plane_type_index(output,
> -							DRM_PLANE_TYPE_OVERLAY,
> -							i);
> -		igt_assert(plane);
> -
> -		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> -					 result_surface, allow_scaling,
> -					 allow_yuv);
> -	}
> -
> -	cairo_surface_destroy(result_surface);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&result_fb);
> -
> -	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == 1);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		chamelium_assert_crc_eq_or_dump(data->chamelium,
> -						expected_crc, crc,
> -						&result_fb, 0);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &result_fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	for (i = 0; i < overlay_planes_count; i++)
> -		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> -
> -	free(overlay_fbs);
> -
> -	igt_remove_fb(data->drm_fd, &primary_fb);
> -	igt_remove_fb(data->drm_fd, &result_fb);
> -}
> -
> -static const char test_hpd_without_ddc_desc[] =
> -	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> -static void
> -test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -	igt_flush_uevents(mon);
> -
> -	/* Disable the DDC on the connector and make sure we still get a
> -	 * hotplug
> -	 */
> -	chamelium_port_set_ddc_state(data->chamelium, port, false);
> -	chamelium_plug(data->chamelium, port);
> -
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -						  data->chamelium, port),
> -						  DRM_MODE_CONNECTED);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_hpd_storm_detect_desc[] =
> -	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> -	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> -	"storm";
> -static void
> -test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
> -{
> -	struct udev_monitor *mon;
> -	int count = 0;
> -
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> -
> -	mon = igt_watch_uevents();
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -
> -	/*
> -	 * Polling should have been enabled by the HPD storm at this point,
> -	 * so we should only get at most 1 hotplug event
> -	 */
> -	igt_until_timeout(5)
> -		count += igt_hotplug_detected(mon, 1);
> -	igt_assert_lt(count, 2);
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_hpd_storm_disable_desc[] =
> -	"Disable HPD storm detection, trigger a storm and check the kernel "
> -	"doesn't detect one";
> -static void
> -test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
> -{
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	chamelium_fire_hpd_pulses(data->chamelium, port,
> -				  width, 10);
> -	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> -
> -	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,
> -				   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;
> -
> -		monitor_edid *edid = &edids_list[i];
> -		igt_info("Testing out the EDID for %s\n",
> -			 monitor_edid_get_name(edid));
> -
> -		/* Getting and Setting the EDID on Chamelium. */
> -		chamelium_edid =
> -			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> -}
> -
> -static const char igt_edid_resolution_list_desc[] =
> -	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> -	" screen resolution matches the mode resolution.";
> -
> -static void edid_resolution_list(data_t *data, struct chamelium_port *port)
> -{
> -	struct chamelium *chamelium = data->chamelium;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	drmModeConnector *connector;
> -	drmModeModeInfoPtr modes;
> -	int count_modes;
> -	int i;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	chamelium_unplug(chamelium, port);
> -	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> -
> -	igt_flush_uevents(mon);
> -	chamelium_plug(chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
> -	igt_flush_uevents(mon);
> -
> -	connector = chamelium_port_get_connector(chamelium, port, true);
> -	modes = connector->modes;
> -	count_modes = connector->count_modes;
> -
> -	output = get_output_for_port(data, port);
> -	pipe = get_pipe_for_output(&data->display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	for (i = 0; i < count_modes; ++i)
> -		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> -
> -	for (i = 0; i < count_modes; ++i) {
> -		struct igt_fb fb = { 0 };
> -		bool is_video_stable;
> -		int screen_res_w, screen_res_h;
> -
> -		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> -			 modes[i].vrefresh);
> -
> -		/* Set the screen mode with the one we chose. */
> -		create_fb_for_mode(data, &fb, &modes[i]);
> -		enable_output(data, port, output, &modes[i], &fb);
> -		is_video_stable = chamelium_port_wait_video_input_stable(
> -			chamelium, port, 10);
> -		igt_assert(is_video_stable);
> -
> -		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> -					      &screen_res_h);
> -		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> -		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	drmModeFreeConnector(connector);
> -}
> -
> -#define for_each_port(p, port)            \
> -	for (p = 0, port = data.ports[p]; \
> -	     p < data.port_count;         \
> -	     p++, port = data.ports[p])
> -
> -#define connector_subtest(name__, type__)                    \
> -	igt_subtest(name__)                                  \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -#define connector_dynamic_subtest(name__, type__)            \
> -	igt_subtest_with_dynamic(name__)                     \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -
> -static data_t data;
> -
> -IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> -igt_main
> -{
> -	struct chamelium_port *port;
> -	int p;
> -	size_t i;
> -
> -	igt_fixture {
> -		/* So fbcon doesn't try to reprobe things itself */
> -		kmstest_set_vt_graphics_mode();
> -
> -		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
> -		igt_display_require(&data.display, data.drm_fd);
> -		igt_require(data.display.is_atomic);
> -
> -		/*
> -		 * XXX: disabling modeset, can be removed when
> -		 * igt_display_require will start doing this for us
> -		 */
> -		igt_display_commit2(&data.display, COMMIT_ATOMIC);
> -
> -		/* we need to initalize chamelium after igt_display_require */
> -		data.chamelium = chamelium_init(data.drm_fd, &data.display);
> -		igt_require(data.chamelium);
> -
> -		data.ports = chamelium_get_ports(data.chamelium,
> -						 &data.port_count);
> -
> -		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> -			data.edids[i] = chamelium_new_edid(data.chamelium,
> -							   igt_kms_get_custom_edid(i));
> -		}
> -	}
> -
> -	igt_describe("DisplayPort tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-fast", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("dp-edid-read", DisplayPort) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> -					       ARRAY_SIZE(DP_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-non-4k",
> -				  DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> -					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> -
> -		igt_describe(igt_edid_resolution_list_desc);
> -		connector_subtest("dp-edid-resolution-list", DisplayPort)
> -			edid_resolution_list(&data, port);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("dp-hpd-storm", DisplayPort)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-single", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("dp-crc-fast", DisplayPort)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-multiple", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("dp-frame-dump", DisplayPort)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("dp-mode-timings", DisplayPort)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("dp-audio", DisplayPort)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("dp-audio-edid", DisplayPort)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("HDMI tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-fast", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("hdmi-edid-read", HDMIA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("hdmi-hpd-storm", HDMIA)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-single", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("hdmi-crc-fast", HDMIA)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-multiple", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CRC, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-crc-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CRC);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (!igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CHECKERBOARD);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("hdmi-frame-dump", HDMIA)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("hdmi-mode-timings", HDMIA)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("hdmi-audio", HDMIA)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("hdmi-audio-edid", HDMIA)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_aspect_ratio_desc);
> -		connector_subtest("hdmi-aspect-ratio", HDMIA)
> -			test_display_aspect_ratio(&data, port);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("VGA tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-fast", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("vga-edid-read", VGA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-suspend", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-hibernate", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_without_ddc_desc);
> -		connector_subtest("vga-hpd-without-ddc", VGA)
> -			test_hpd_without_ddc(&data, port);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("vga-frame-dump", VGA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_ANALOG, 1);
> -	}
> -
> -	igt_describe("Tests that operate on all connectors");
> -	igt_subtest_group {
> -
> -		igt_fixture {
> -			igt_require(data.port_count);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-suspend")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_MEM,
> -						       SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-hibernate")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_DISK,
> -						       SUSPEND_TEST_DEVICES);
> -	}
> -
> -	igt_describe(test_hotplug_for_each_pipe_desc);
> -	connector_subtest("vga-hpd-for-each-pipe", VGA)
> -		test_hotplug_for_each_pipe(&data, port);
> -
> -	igt_fixture {
> -		igt_display_fini(&data.display);
> -		close(data.drm_fd);
> -	}
> -}
> diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
> new file mode 100644
> index 00000000..4d13744c
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_audio.c
> @@ -0,0 +1,858 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the Audio functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +/* Playback parameters control the audio signal we synthesize and send */
> +#define PLAYBACK_CHANNELS 2
> +#define PLAYBACK_SAMPLES 1024
> +
> +/* Capture paremeters control the audio signal we receive */
> +#define CAPTURE_SAMPLES 2048
> +
> +#define AUDIO_TIMEOUT 2000 /* ms */
> +/* A streak of 3 gives confidence that the signal is good. */
> +#define MIN_STREAK 3
> +
> +#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> +#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> +#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> +
> +struct audio_state {
> +	struct alsa *alsa;
> +	struct chamelium *chamelium;
> +	struct chamelium_port *port;
> +	struct chamelium_stream *stream;
> +
> +	/* The capture format is only available after capture has started. */
> +	struct {
> +		snd_pcm_format_t format;
> +		int channels;
> +		int rate;
> +	} playback, capture;
> +
> +	char *name;
> +	struct audio_signal *signal; /* for frequencies test only */
> +	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	size_t recv_pages;
> +	int msec;
> +
> +	int dump_fd;
> +	char *dump_path;
> +
> +	pthread_t thread;
> +	atomic_bool run;
> +	atomic_bool positive; /* for pulse test only */
> +};
> +
> +/* TODO: enable >48KHz rates, these are not reliable */
> +static int test_sampling_rates[] = {
> +	32000, 44100, 48000,
> +	/* 88200, */
> +	/* 96000, */
> +	/* 176400, */
> +	/* 192000, */
> +};
> +
> +static int test_sampling_rates_count =
> +	sizeof(test_sampling_rates) / sizeof(int);
> +
> +/* Test frequencies (Hz): a sine signal will be generated for each.
> + *
> + * Depending on the sampling rate chosen, it might not be possible to properly
> + * detect the generated sine (see Nyquist–Shannon sampling theorem).
> + * Frequencies that can't be reliably detected will be automatically pruned in
> + * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> + * tested with a 192KHz sampling rate.
> + */
> +static int test_frequencies[] = {
> +	300, 600, 1200, 10000, 80000,
> +};
> +
> +static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> +
> +static const snd_pcm_format_t test_formats[] = {
> +	SND_PCM_FORMAT_S16_LE,
> +	SND_PCM_FORMAT_S24_LE,
> +	SND_PCM_FORMAT_S32_LE,
> +};
> +
> +static const size_t test_formats_count =
> +	sizeof(test_formats) / sizeof(test_formats[0]);
> +
> +static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
> +			     struct alsa *alsa, struct chamelium_port *port,
> +			     snd_pcm_format_t format, int channels, int rate)
> +{
> +	memset(state, 0, sizeof(*state));
> +	state->dump_fd = -1;
> +
> +	state->alsa = alsa;
> +	state->chamelium = data->chamelium;
> +	state->port = port;
> +
> +	state->playback.format = format;
> +	state->playback.channels = channels;
> +	state->playback.rate = rate;
> +
> +	alsa_configure_output(alsa, format, channels, rate);
> +
> +	state->stream = chamelium_stream_init();
> +	igt_assert_f(state->stream,
> +		     "Failed to initialize Chamelium stream client\n");
> +}
> +
> +static void audio_state_fini(struct audio_state *state)
> +{
> +	chamelium_stream_deinit(state->stream);
> +	free(state->name);
> +}
> +
> +static void *run_audio_thread(void *data)
> +{
> +	struct alsa *alsa = data;
> +
> +	alsa_run(alsa, -1);
> +	return NULL;
> +}
> +
> +static void audio_state_start(struct audio_state *state, const char *name)
> +{
> +	int ret;
> +	bool ok;
> +	size_t i, j;
> +	enum chamelium_stream_realtime_mode stream_mode;
> +	char dump_suffix[64];
> +
> +	free(state->name);
> +	state->name = strdup(name);
> +	state->recv_pages = 0;
> +	state->msec = 0;
> +
> +	igt_debug("Starting %s test with playback format %s, "
> +		  "sampling rate %d Hz and %d channels\n",
> +		  name, snd_pcm_format_name(state->playback.format),
> +		  state->playback.rate, state->playback.channels);
> +
> +	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> +
> +	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> +	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> +	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> +
> +	/* Start playing audio */
> +	state->run = true;
> +	ret = pthread_create(&state->thread, NULL, run_audio_thread,
> +			     state->alsa);
> +	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> +
> +	/* The Chamelium device only supports this PCM format. */
> +	state->capture.format = SND_PCM_FORMAT_S32_LE;
> +
> +	/* Only after we've started playing audio, we can retrieve the capture
> +	 * format used by the Chamelium device. */
> +	chamelium_get_audio_format(state->chamelium, state->port,
> +				   &state->capture.rate,
> +				   &state->capture.channels);
> +	if (state->capture.rate == 0) {
> +		igt_debug("Audio receiver doesn't indicate the capture "
> +			  "sampling rate, assuming it's %d Hz\n",
> +			  state->playback.rate);
> +		state->capture.rate = state->playback.rate;
> +	}
> +
> +	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> +					    state->channel_mapping);
> +	/* Make sure we can capture all channels we send. */
> +	for (i = 0; i < state->playback.channels; i++) {
> +		ok = false;
> +		for (j = 0; j < state->capture.channels; j++) {
> +			if (state->channel_mapping[j] == i) {
> +				ok = true;
> +				break;
> +			}
> +		}
> +		igt_assert_f(ok, "Cannot capture all channels\n");
> +	}
> +
> +	if (igt_frame_dump_is_enabled()) {
> +		snprintf(dump_suffix, sizeof(dump_suffix),
> +			 "capture-%s-%s-%dch-%dHz", name,
> +			 snd_pcm_format_name(state->playback.format),
> +			 state->playback.channels, state->playback.rate);
> +
> +		state->dump_fd = audio_create_wav_file_s32_le(
> +			dump_suffix, state->capture.rate,
> +			state->capture.channels, &state->dump_path);
> +		igt_assert_f(state->dump_fd >= 0,
> +			     "Failed to create audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_receive(struct audio_state *state, int32_t **recv,
> +				size_t *recv_len)
> +{
> +	bool ok;
> +	size_t page_count;
> +	size_t recv_size;
> +
> +	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
> +						     recv, recv_len);
> +	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> +
> +	state->msec = state->recv_pages * *recv_len /
> +		      (double)state->capture.channels /
> +		      (double)state->capture.rate * 1000;
> +	state->recv_pages++;
> +
> +	if (state->dump_fd >= 0) {
> +		recv_size = *recv_len * sizeof(int32_t);
> +		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
> +				     recv_size,
> +			     "Failed to write to audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_stop(struct audio_state *state, bool success)
> +{
> +	bool ok;
> +	int ret;
> +	struct chamelium_audio_file *audio_file;
> +	enum igt_log_level log_level;
> +
> +	igt_debug("Stopping audio playback\n");
> +	state->run = false;
> +	ret = pthread_join(state->thread, NULL);
> +	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> +
> +	ok = chamelium_stream_stop_realtime_audio(state->stream);
> +	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> +
> +	audio_file =
> +		chamelium_stop_capturing_audio(state->chamelium, state->port);
> +	if (audio_file) {
> +		igt_debug("Audio file saved on the Chamelium in %s\n",
> +			  audio_file->path);
> +		chamelium_destroy_audio_file(audio_file);
> +	}
> +
> +	if (state->dump_fd >= 0) {
> +		close(state->dump_fd);
> +		state->dump_fd = -1;
> +
> +		if (success) {
> +			/* Test succeeded, no need to keep the captured data */
> +			unlink(state->dump_path);
> +		} else
> +			igt_debug("Saved captured audio data to %s\n",
> +				  state->dump_path);
> +		free(state->dump_path);
> +		state->dump_path = NULL;
> +	}
> +
> +	if (success)
> +		log_level = IGT_LOG_DEBUG;
> +	else
> +		log_level = IGT_LOG_CRITICAL;
> +
> +	igt_log(IGT_LOG_DOMAIN, log_level,
> +		"Audio %s test result for format %s, "
> +		"sampling rate %d Hz and %d channels: %s\n",
> +		state->name, snd_pcm_format_name(state->playback.format),
> +		state->playback.rate, state->playback.channels,
> +		success ? "ALL GREEN" : "FAILED");
> +}
> +
> +static void check_audio_infoframe(struct audio_state *state)
> +{
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_audio infoframe_audio;
> +	struct infoframe_audio expected = { 0 };
> +	bool ok;
> +
> +	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "Chamelium board doesn't support GetLastInfoFrame\n");
> +		return;
> +	}
> +
> +	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> +	expected.channel_count = state->playback.channels;
> +	expected.sampling_freq = state->playback.rate;
> +	expected.sample_size = snd_pcm_format_width(state->playback.format);
> +
> +	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> +						 CHAMELIUM_INFOFRAME_AUDIO);
> +	if (infoframe == NULL && state->playback.channels <= 2) {
> +		/* Audio InfoFrames are optional for mono and stereo audio */
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "no InfoFrame received\n");
> +		return;
> +	}
> +	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> +
> +	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> +				   infoframe->payload, infoframe->payload_size);
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> +
> +	igt_debug("Checking audio InfoFrame:\n");
> +	igt_debug("coding_type: got %d, expected %d\n",
> +		  infoframe_audio.coding_type, expected.coding_type);
> +	igt_debug("channel_count: got %d, expected %d\n",
> +		  infoframe_audio.channel_count, expected.channel_count);
> +	igt_debug("sampling_freq: got %d, expected %d\n",
> +		  infoframe_audio.sampling_freq, expected.sampling_freq);
> +	igt_debug("sample_size: got %d, expected %d\n",
> +		  infoframe_audio.sample_size, expected.sample_size);
> +
> +	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> +		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> +	if (infoframe_audio.channel_count >= 0)
> +		igt_assert(infoframe_audio.channel_count ==
> +			   expected.channel_count);
> +	if (infoframe_audio.sampling_freq >= 0)
> +		igt_assert(infoframe_audio.sampling_freq ==
> +			   expected.sampling_freq);
> +	if (infoframe_audio.sample_size >= 0)
> +		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> +}
> +
> +static int audio_output_frequencies_callback(void *data, void *buffer,
> +					     int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	audio_signal_fill(state->signal, tmp, samples);
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool test_audio_frequencies(struct audio_state *state)
> +{
> +	int freq, step;
> +	int32_t *recv, *buf;
> +	double *channel;
> +	size_t i, j, streak;
> +	size_t recv_len, buf_len, buf_cap, channel_len;
> +	bool success;
> +	int capture_chan;
> +
> +	state->signal = audio_signal_init(state->playback.channels,
> +					  state->playback.rate);
> +	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> +
> +	/* We'll choose different frequencies per channel to make sure they are
> +	 * independent from each other. To do so, we'll add a different offset
> +	 * to the base frequencies for each channel. We need to choose a big
> +	 * enough offset so that we're sure to detect mixed up channels. We
> +	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> +	 * difference.
> +	 *
> +	 * Note that we assume capture_rate == playback_rate. We'll assert this
> +	 * later on. We cannot retrieve the capture rate before starting
> +	 * playing audio, so we don't really have the choice.
> +	 */
> +	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> +	for (i = 0; i < test_frequencies_count; i++) {
> +		for (j = 0; j < state->playback.channels; j++) {
> +			freq = test_frequencies[i] + j * step;
> +			audio_signal_add_frequency(state->signal, freq, j);
> +		}
> +	}
> +	audio_signal_synthesize(state->signal);
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_frequencies_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	audio_state_start(state, "frequencies");
> +
> +	igt_assert_f(state->capture.rate == state->playback.rate,
> +		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> +		     state->capture.rate, state->playback.rate);
> +
> +	/* Needs to be a multiple of 128, because that's the number of samples
> +	 * we get per channel each time we receive an audio page from the
> +	 * Chamelium device.
> +	 *
> +	 * Additionally, this value needs to be high enough to guarantee we
> +	 * capture a full period of each sine we generate. If we capture 2048
> +	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> +	 * sines. For lower sampling rates, the capture duration will be
> +	 * longer.
> +	 */
> +	channel_len = CAPTURE_SAMPLES;
> +	channel = malloc(sizeof(double) * channel_len);
> +
> +	buf_cap = state->capture.channels * channel_len;
> +	buf = malloc(sizeof(int32_t) * buf_cap);
> +	buf_len = 0;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +
> +	success = false;
> +	streak = 0;
> +	while (!success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> +		buf_len += recv_len;
> +
> +		if (buf_len < buf_cap)
> +			continue;
> +		igt_assert(buf_len == buf_cap);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (j = 0; j < state->playback.channels; j++) {
> +			capture_chan = state->channel_mapping[j];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  j, capture_chan);
> +
> +			audio_extract_channel_s32_le(channel, channel_len, buf,
> +						     buf_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			if (audio_signal_detect(state->signal,
> +						state->capture.rate, j, channel,
> +						channel_len))
> +				streak++;
> +			else
> +				streak = 0;
> +		}
> +
> +		buf_len = 0;
> +
> +		success = streak == MIN_STREAK * state->playback.channels;
> +	}
> +
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +	free(buf);
> +	free(channel);
> +	audio_signal_fini(state->signal);
> +
> +	check_audio_infoframe(state);
> +
> +	return success;
> +}
> +
> +static int audio_output_flatline_callback(void *data, void *buffer, int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len, i;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	for (i = 0; i < len; i++)
> +		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> +{
> +	double expected, min, max;
> +	size_t i;
> +	bool ok;
> +
> +	min = max = NAN;
> +	for (i = 0; i < buf_len; i++) {
> +		if (isnan(min) || buf[i] < min)
> +			min = buf[i];
> +		if (isnan(max) || buf[i] > max)
> +			max = buf[i];
> +	}
> +
> +	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> +	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> +	if (ok)
> +		igt_debug("Flatline wave amplitude detected\n");
> +	else
> +		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> +			  min, max);
> +	return ok;
> +}
> +
> +static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> +{
> +	size_t i;
> +
> +	for (i = 0; i < buf_len; i++) {
> +		if (buf[i] < 0)
> +			return i;
> +	}
> +
> +	return -1;
> +}
> +
> +/** test_audio_flatline:
> + *
> + * Send a constant value (one positive, then a negative one) and check that:
> + *
> + * - The amplitude of the flatline is correct
> + * - All channels switch from a positive signal to a negative one at the same
> + *   time (ie. all channels are aligned)
> + */
> +static bool test_audio_flatline(struct audio_state *state)
> +{
> +	bool success, amp_success, align_success;
> +	int32_t *recv;
> +	size_t recv_len, i, channel_len;
> +	ssize_t j;
> +	int streak, capture_chan;
> +	double *channel;
> +	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_flatline_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	/* Start by sending a positive signal */
> +	state->positive = true;
> +
> +	audio_state_start(state, "flatline");
> +
> +	for (i = 0; i < state->playback.channels; i++)
> +		falling_edges[i] = -1;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +	amp_success = false;
> +	streak = 0;
> +	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (i = 0; i < state->playback.channels; i++) {
> +			capture_chan = state->channel_mapping[i];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  i, capture_chan);
> +
> +			channel_len = audio_extract_channel_s32_le(
> +				NULL, 0, recv, recv_len,
> +				state->capture.channels, capture_chan);
> +			channel = malloc(channel_len * sizeof(double));
> +			audio_extract_channel_s32_le(channel, channel_len, recv,
> +						     recv_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			/* Check whether the amplitude is fine */
> +			if (detect_flatline_amplitude(channel, channel_len,
> +						      state->positive))
> +				streak++;
> +			else
> +				streak = 0;
> +
> +			/* If we're now sending a negative signal, detect the
> +			 * falling edge */
> +			j = detect_falling_edge(channel, channel_len);
> +			if (!state->positive && j >= 0) {
> +				falling_edges[i] =
> +					recv_len * state->recv_pages + j;
> +			}
> +
> +			free(channel);
> +		}
> +
> +		amp_success = streak == MIN_STREAK * state->playback.channels;
> +
> +		if (amp_success && state->positive) {
> +			/* Switch to a negative signal after we've detected the
> +			 * positive one. */
> +			state->positive = false;
> +			amp_success = false;
> +			streak = 0;
> +			igt_debug("Switching to negative square wave\n");
> +		}
> +	}
> +
> +	/* Check alignment between all channels by comparing the index of the
> +	 * falling edge. */
> +	align_success = true;
> +	for (i = 0; i < state->playback.channels; i++) {
> +		if (falling_edges[i] < 0) {
> +			igt_critical(
> +				"Falling edge not detected for channel %zu\n",
> +				i);
> +			align_success = false;
> +			continue;
> +		}
> +
> +		if (abs(falling_edges[0] - falling_edges[i]) >
> +		    FLATLINE_ALIGN_ACCURACY) {
> +			igt_critical("Channel alignment mismatch: "
> +				     "channel 0 has a falling edge at index %d "
> +				     "while channel %zu has index %d\n",
> +				     falling_edges[0], i, falling_edges[i]);
> +			align_success = false;
> +		}
> +	}
> +
> +	success = amp_success && align_success;
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +
> +	return success;
> +}
> +
> +static bool check_audio_configuration(struct alsa *alsa,
> +				      snd_pcm_format_t format, int channels,
> +				      int sampling_rate)
> +{
> +	if (!alsa_test_output_configuration(alsa, format, channels,
> +					    sampling_rate)) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because at least one of the "
> +			  "selected output devices doesn't support this "
> +			  "configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	/* TODO: the Chamelium device sends a malformed signal for some audio
> +	 * configurations. See crbug.com/950917 */
> +	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> +	    channels > 2) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because the Chamelium device "
> +			  "doesn't support this configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	return true;
> +}
> +
> +static const char test_display_audio_desc[] =
> +	"Playback various audio signals with various audio formats/rates, "
> +	"capture them and check they are correct";
> +static void test_display_audio(chamelium_data_t *data,
> +			       struct chamelium_port *port,
> +			       const char *audio_device,
> +			       enum igt_custom_edid_type edid)
> +{
> +	bool run, success;
> +	struct alsa *alsa;
> +	int ret;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id, i, j;
> +	int channels, sampling_rate;
> +	snd_pcm_format_t format;
> +	struct audio_state state;
> +
> +	igt_require(alsa_has_exclusive_access());
> +
> +	/* Old Chamelium devices need an update for DisplayPort audio and
> +	 * chamelium_get_audio_format support. */
> +	igt_require(chamelium_has_audio_support(data->chamelium, port));
> +
> +	alsa = alsa_init();
> +	igt_assert(alsa);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because the receiver won't try to receive audio if
> +	 * it doesn't receive video. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	run = false;
> +	success = true;
> +	for (i = 0; i < test_sampling_rates_count; i++) {
> +		for (j = 0; j < test_formats_count; j++) {
> +			ret = alsa_open_output(alsa, audio_device);
> +			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> +
> +			/* TODO: playback on all 8 available channels (this
> +			 * isn't supported by Chamelium devices yet, see
> +			 * https://crbug.com/950917) */
> +			format = test_formats[j];
> +			channels = PLAYBACK_CHANNELS;
> +			sampling_rate = test_sampling_rates[i];
> +
> +			if (!check_audio_configuration(alsa, format, channels,
> +						       sampling_rate))
> +				continue;
> +
> +			run = true;
> +
> +			audio_state_init(&state, data, alsa, port, format,
> +					 channels, sampling_rate);
> +			success &= test_audio_frequencies(&state);
> +			success &= test_audio_flatline(&state);
> +			audio_state_fini(&state);
> +
> +			alsa_close_output(alsa);
> +		}
> +	}
> +
> +	/* Make sure we tested at least one frequency and format. */
> +	igt_assert(run);
> +	/* Make sure all runs were successful. */
> +	igt_assert(success);
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +
> +	free(alsa);
> +}
> +
> +static const char test_display_audio_edid_desc[] =
> +	"Plug a connector with an EDID suitable for audio, check ALSA's "
> +	"EDID-Like Data reports the correct audio parameters";
> +static void test_display_audio_edid(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_custom_edid_type edid)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id;
> +	struct eld_entry eld;
> +	struct eld_sad *sad;
> +
> +	igt_require(eld_is_supported());
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because audio cannot be played on inactive
> +	 * connectors. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	igt_assert(eld_get_igt(&eld));
> +	igt_assert(eld.sads_len == 1);
> +
> +	sad = &eld.sads[0];
> +	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> +	igt_assert(sad->channels == 2);
> +	igt_assert(sad->rates ==
> +		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
> +		    CEA_SAD_SAMPLING_RATE_48KHZ));
> +	igt_assert(sad->bits ==
> +		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
> +		    CEA_SAD_SAMPLE_SIZE_24));
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("dp-audio", DisplayPort) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("dp-audio-edid", DisplayPort)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_DP_AUDIO);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("hdmi-audio-edid", HDMIA)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_HDMI_AUDIO);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
> similarity index 100%
> rename from tests/chamelium/kms_color_chamelium.c
> rename to tests/chamelium/kms_chamelium_color.c
> diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
> new file mode 100644
> index 00000000..6c069112
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_edid.c
> @@ -0,0 +1,532 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the EDID functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_chamelium.h"
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +#include "monitor_edids/dp_edids.h"
> +#include "monitor_edids/hdmi_edids.h"
> +#include "monitor_edids/monitor_edids_helper.h"
> +
> +#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> +
> +static void get_connectors_link_status_failed(chamelium_data_t *data,
> +					      bool *link_status_failed)
> +{
> +	drmModeConnector *connector;
> +	uint64_t link_status;
> +	drmModePropertyPtr prop;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		connector = chamelium_port_get_connector(data->chamelium,
> +							 data->ports[p], false);
> +
> +		igt_assert(kmstest_get_property(
> +			data->drm_fd, connector->connector_id,
> +			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
> +			&link_status, &prop));
> +
> +		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> +
> +		drmModeFreeProperty(prop);
> +		drmModeFreeConnector(connector);
> +	}
> +}
> +
> +static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> +		       drmModeModeInfo *mode)
> +{
> +	struct chamelium_video_params video_params = { 0 };
> +	double mode_clock;
> +	int mode_hsync_offset, mode_vsync_offset;
> +	int mode_hsync_width, mode_vsync_width;
> +	int mode_hsync_polarity, mode_vsync_polarity;
> +
> +	chamelium_port_get_video_params(chamelium, port, &video_params);
> +
> +	mode_clock = (double)mode->clock / 1000;
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> +		/* this is what chamelium understands as offsets for DP */
> +		mode_hsync_offset = mode->htotal - mode->hsync_start;
> +		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> +	} else {
> +		/* and this is what they are for other connectors */
> +		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> +		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> +	}
> +
> +	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> +	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> +
> +	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> +	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> +
> +	igt_debug("Checking video mode:\n");
> +	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
> +		  mode_clock, MODE_CLOCK_ACCURACY * 100);
> +	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
> +		  mode->hdisplay);
> +	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
> +		  mode->vdisplay);
> +	igt_debug("hsync_offset: got %d, expected %d\n",
> +		  video_params.hsync_offset, mode_hsync_offset);
> +	igt_debug("vsync_offset: got %d, expected %d\n",
> +		  video_params.vsync_offset, mode_vsync_offset);
> +	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
> +		  mode->htotal);
> +	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
> +		  mode->vtotal);
> +	igt_debug("hsync_width: got %d, expected %d\n",
> +		  video_params.hsync_width, mode_hsync_width);
> +	igt_debug("vsync_width: got %d, expected %d\n",
> +		  video_params.vsync_width, mode_vsync_width);
> +	igt_debug("hsync_polarity: got %d, expected %d\n",
> +		  video_params.hsync_polarity, mode_hsync_polarity);
> +	igt_debug("vsync_polarity: got %d, expected %d\n",
> +		  video_params.vsync_polarity, mode_vsync_polarity);
> +
> +	if (!isnan(video_params.clock)) {
> +		igt_assert(video_params.clock >
> +			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> +		igt_assert(video_params.clock <
> +			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> +	}
> +	igt_assert(video_params.hactive == mode->hdisplay);
> +	igt_assert(video_params.vactive == mode->vdisplay);
> +	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> +	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> +	igt_assert(video_params.htotal == mode->htotal);
> +	igt_assert(video_params.vtotal == mode->vtotal);
> +	igt_assert(video_params.hsync_width == mode_hsync_width);
> +	igt_assert(video_params.vsync_width == mode_vsync_width);
> +	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> +	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> +}
> +
> +static const char igt_custom_edid_type_read_desc[] =
> +	"Make sure the EDID exposed by KMS is the same as the screen's";
> +static void igt_custom_edid_type_read(chamelium_data_t *data,
> +				      struct chamelium_port *port,
> +				      enum igt_custom_edid_type edid)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector;
> +	size_t raw_edid_size;
> +	const struct edid *raw_edid;
> +	uint64_t edid_blob_id;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_skip_on(chamelium_check_analog_bridge(data, port));
> +
> +	connector = chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob_id != 0);
> +	igt_assert(edid_blob =
> +			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
> +
> +	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> +	raw_edid_size = edid_get_size(raw_edid);
> +	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +}
> +
> +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(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   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;
> +
> +		monitor_edid *edid = &edids_list[i];
> +		igt_info("Testing out the EDID for %s\n",
> +			 monitor_edid_get_name(edid));
> +
> +		/* Getting and Setting the EDID on Chamelium. */
> +		chamelium_edid =
> +			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> +		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
> +		chamelium_create_fb_for_mode(data, &fb, &mode);
> +		output = chamelium_get_output_for_port(data, port);
> +		pipe = chamelium_get_pipe_for_output(&data->display, output);
> +		igt_output_set_pipe(output, pipe);
> +		chamelium_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);
> +}
> +
> +static const char igt_edid_resolution_list_desc[] =
> +	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> +	" screen resolution matches the mode resolution.";
> +
> +static void edid_resolution_list(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct chamelium *chamelium = data->chamelium;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	drmModeConnector *connector;
> +	drmModeModeInfoPtr modes;
> +	int count_modes;
> +	int i;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	chamelium_unplug(chamelium, port);
> +	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> +
> +	igt_flush_uevents(mon);
> +	chamelium_plug(chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_CONNECTED);
> +	igt_flush_uevents(mon);
> +
> +	connector = chamelium_port_get_connector(chamelium, port, true);
> +	modes = connector->modes;
> +	count_modes = connector->count_modes;
> +
> +	output = chamelium_get_output_for_port(data, port);
> +	pipe = chamelium_get_pipe_for_output(&data->display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	for (i = 0; i < count_modes; ++i)
> +		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> +
> +	for (i = 0; i < count_modes; ++i) {
> +		struct igt_fb fb = { 0 };
> +		bool is_video_stable;
> +		int screen_res_w, screen_res_h;
> +
> +		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> +			 modes[i].vrefresh);
> +
> +		/* Set the screen mode with the one we chose. */
> +		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
> +		chamelium_enable_output(data, port, output, &modes[i], &fb);
> +		is_video_stable = chamelium_port_wait_video_input_stable(
> +			chamelium, port, 10);
> +		igt_assert(is_video_stable);
> +
> +		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> +					      &screen_res_h);
> +		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> +		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_suspend_resume_edid_change_desc[] =
> +	"Simulate a screen being unplugged and another screen being plugged "
> +	"during suspend, check that a uevent is sent and connector status is "
> +	"updated";
> +static void test_suspend_resume_edid_change(chamelium_data_t *data,
> +					    struct chamelium_port *port,
> +					    enum igt_suspend_state state,
> +					    enum igt_suspend_test test,
> +					    enum igt_custom_edid_type edid,
> +					    enum igt_custom_edid_type alt_edid)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	bool link_status_failed[2][data->port_count];
> +	int p;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Catch the event and flush all remaining ones. */
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_flush_uevents(mon);
> +
> +	/* First plug in the port */
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	/*
> +	 * Change the edid before we suspend. On resume, the machine should
> +	 * notice the EDID change and fire a hotplug event.
> +	 */
> +	chamelium_set_edid(data, port, alt_edid);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[0]);
> +
> +	igt_flush_uevents(mon);
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[1]);
> +
> +	for (p = 0; p < data->port_count; p++)
> +		igt_skip_on(!link_status_failed[0][p] &&
> +			    link_status_failed[1][p]);
> +}
> +
> +static const char test_mode_timings_desc[] =
> +	"For each mode of the IGT base EDID, perform a modeset and check the "
> +	"mode detected by the Chamelium receiver matches the mode we set";
> +static void test_mode_timings(chamelium_data_t *data,
> +			      struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	igt_require(chamelium_supports_get_video_params(data->chamelium));
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +		int fb_id;
> +		struct igt_fb fb;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		/* Trigger the FSM */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> +
> +		check_mode(data->chamelium, port, mode);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("dp-edid-read", DisplayPort)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> +					       ARRAY_SIZE(DP_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-non-4k",
> +				  DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> +					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> +
> +		igt_describe(igt_edid_resolution_list_desc);
> +		connector_subtest("dp-edid-resolution-list", DisplayPort)
> +			edid_resolution_list(&data, port);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-hibernate",
> +				  DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("dp-mode-timings", DisplayPort)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("hdmi-edid-read", HDMIA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("hdmi-mode-timings", HDMIA)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("vga-edid-read", VGA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
> new file mode 100644
> index 00000000..008bc34b
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_frames.c
> @@ -0,0 +1,1085 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Lyude Paul <lyude@redhat.com>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +#define connector_dynamic_subtest(name__, type__)                   \
> +	igt_subtest_with_dynamic(name__)                            \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +struct vic_mode {
> +	int hactive, vactive;
> +	int vrefresh; /* Hz */
> +	uint32_t picture_ar;
> +};
> +
> +static int chamelium_vga_modes[][2] = {
> +	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
> +	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
> +	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
> +	{ 640, 480 },	{ -1, -1 },
> +};
> +
> +/* Maps Video Identification Codes to a mode */
> +static const struct vic_mode vic_modes[] = {
> +	[16] = {
> +		.hactive = 1920,
> +		.vactive = 1080,
> +		.vrefresh = 60,
> +		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> +	},
> +};
> +
> +/* Maps aspect ratios to their mode flag */
> +static const uint32_t mode_ar_flags[] = {
> +	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> +};
> +
> +static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
> +{
> +	int i = 0;
> +
> +	while (chamelium_vga_modes[i][0] != -1) {
> +		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> +		    mode->vdisplay == chamelium_vga_modes[i][1])
> +			return false;
> +
> +		i++;
> +	}
> +
> +	return true;
> +}
> +
> +static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
> +			    igt_output_t *output, drmModeModeInfo *mode,
> +			    uint32_t fourcc, enum chamelium_check check,
> +			    int count)
> +{
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	struct igt_fb frame_fb, fb;
> +	int i, fb_id, captured_frame_count;
> +	int frame_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &fb);
> +	igt_assert(fb_id > 0);
> +
> +	frame_id =
> +		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
> +	igt_assert(frame_id > 0);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&fb);
> +
> +	chamelium_enable_output(data, port, output, mode, &frame_fb);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		igt_crc_t *expected_crc;
> +		igt_crc_t *crc;
> +
> +		/* We want to keep the display running for a little bit, since
> +		 * there's always the potential the driver isn't able to keep
> +		 * the display running properly for very long
> +		 */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == count);
> +
> +		igt_debug("Captured %d frames\n", captured_frame_count);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		for (i = 0; i < captured_frame_count; i++)
> +			chamelium_assert_crc_eq_or_dump(
> +				data->chamelium, expected_crc, &crc[i], &fb, i);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> +		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		igt_assert(count == 1);
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG)
> +			chamelium_crop_analog_frame(dump, mode->hdisplay,
> +						    mode->vdisplay);
> +
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	igt_remove_fb(data->drm_fd, &frame_fb);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static enum infoframe_avi_picture_aspect_ratio
> +get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> +{
> +	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> +	switch (aspect_ratio) {
> +	case DRM_MODE_PICTURE_ASPECT_4_3:
> +		return INFOFRAME_AVI_PIC_AR_4_3;
> +	case DRM_MODE_PICTURE_ASPECT_16_9:
> +		return INFOFRAME_AVI_PIC_AR_16_9;
> +	default:
> +		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> +	}
> +}
> +
> +static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> +				 drmModeModeInfo *drm_mode)
> +{
> +	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> +
> +	return vic_mode->hactive == drm_mode->hdisplay &&
> +	       vic_mode->vactive == drm_mode->vdisplay &&
> +	       vic_mode->vrefresh == drm_mode->vrefresh &&
> +	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> +}
> +
> +static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
> +				   uint32_t height, uint32_t format,
> +				   uint64_t modifier, size_t *stride)
> +{
> +	size_t stride_min;
> +	uint32_t max_tile_w = 4, tile_w, tile_h;
> +	int i;
> +	struct igt_fb dummy;
> +
> +	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> +
> +	/* Randomize the stride to less than twice the minimum. */
> +	*stride = (rand() % stride_min) + stride_min;
> +
> +	/*
> +	 * Create a dummy FB to determine bpp for each plane, and calculate
> +	 * the maximum tile width from that.
> +	 */
> +	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> +	for (i = 0; i < dummy.num_planes; i++) {
> +		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
> +				     &tile_w, &tile_h);
> +
> +		if (tile_w > max_tile_w)
> +			max_tile_w = tile_w;
> +	}
> +	igt_remove_fb(data->drm_fd, &dummy);
> +
> +	/*
> +	 * Pixman requires the stride to be aligned to 32-bits, which is
> +	 * reflected in the initial value of max_tile_w and the hw
> +	 * may require a multiple of tile width, choose biggest of the 2.
> +	 */
> +	*stride = ALIGN(*stride, max_tile_w);
> +}
> +
> +static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> +				  uint32_t height, uint32_t format,
> +				  uint64_t *modifier)
> +{
> +	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> +		/* Randomize the column height to less than twice the minimum.
> +		 */
> +		size_t column_height = (rand() % height) + height;
> +
> +		igt_debug(
> +			"Selecting VC4 SAND256 tiling with column height %ld\n",
> +			column_height);
> +
> +		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
> +			column_height);
> +	}
> +}
> +
> +static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
> +				  drmModeModeInfo *mode, uint32_t *width,
> +				  uint32_t *height, uint32_t *format,
> +				  uint64_t *modifier, bool allow_yuv)
> +{
> +	int min_dim;
> +	uint32_t idx[plane->format_mod_count];
> +	unsigned int count = 0;
> +	unsigned int i;
> +
> +	/* First pass to count the supported formats. */
> +	for (i = 0; i < plane->format_mod_count; i++)
> +		if (igt_fb_supported_format(plane->formats[i]) &&
> +		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> +			idx[count++] = i;
> +
> +	igt_assert(count > 0);
> +
> +	i = idx[rand() % count];
> +	*format = plane->formats[i];
> +	*modifier = plane->modifiers[i];
> +
> +	update_tiled_modifier(plane, *width, *height, *format, modifier);
> +
> +	/*
> +	 * Randomize width and height in the mode dimensions range.
> +	 *
> +	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> +	 * least min_dim, because src_w = width - (rand % w / 2).
> +	 *
> +	 * Use a minimum dimension of 16 for YUV, because planar YUV
> +	 * subsamples the UV plane.
> +	 */
> +	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> +
> +	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> +	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> +}
> +
> +static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> +			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> +			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> +			    struct igt_fb *fb)
> +{
> +	igt_plane_set_fb(plane, fb);
> +
> +	igt_plane_set_position(plane, crtc_x, crtc_y);
> +	igt_plane_set_size(plane, crtc_w, crtc_h);
> +
> +	igt_fb_set_position(fb, plane, src_x, src_y);
> +	igt_fb_set_size(fb, plane, src_w, src_h);
> +}
> +
> +static void randomize_plane_coordinates(
> +	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
> +	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
> +	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
> +	int32_t *crtc_y, bool allow_scaling)
> +{
> +	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> +	uint32_t width = fb->width, height = fb->height;
> +	double ratio;
> +	int ret;
> +
> +	/* Randomize source offset in the first half of the original size. */
> +	*src_x = rand() % (width / 2);
> +	*src_y = rand() % (height / 2);
> +
> +	/* The source size only includes the active source area. */
> +	*src_w = width - *src_x;
> +	*src_h = height - *src_y;
> +
> +	if (allow_scaling) {
> +		*crtc_w = (rand() % mode->hdisplay) + 1;
> +		*crtc_h = (rand() % mode->vdisplay) + 1;
> +
> +		/*
> +		 * Don't bother with scaling if dimensions are quite close in
> +		 * order to get non-scaling cases more frequently. Also limit
> +		 * scaling to 3x to avoid aggressive filtering that makes
> +		 * comparison less reliable, and don't go above 2x downsampling
> +		 * to avoid possible hw limitations.
> +		 */
> +
> +		ratio = ((double)*crtc_w / *src_w);
> +		if (ratio < 0.5)
> +			*src_w = *crtc_w * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_w = *src_w;
> +		else if (ratio > 3.0)
> +			*crtc_w = *src_w * 3;
> +
> +		ratio = ((double)*crtc_h / *src_h);
> +		if (ratio < 0.5)
> +			*src_h = *crtc_h * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_h = *src_h;
> +		else if (ratio > 3.0)
> +			*crtc_h = *src_h * 3;
> +	} else {
> +		*crtc_w = *src_w;
> +		*crtc_h = *src_h;
> +	}
> +
> +	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> +		/*
> +		 * When scaling is involved, make sure to not go off-bounds or
> +		 * scaled clipping may result in decimal dimensions, that most
> +		 * drivers don't support.
> +		 */
> +		if (*crtc_w < mode->hdisplay)
> +			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> +		else
> +			*crtc_x = 0;
> +
> +		if (*crtc_h < mode->vdisplay)
> +			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> +		else
> +			*crtc_y = 0;
> +	} else {
> +		/*
> +		 * Randomize the on-crtc position and allow the plane to go
> +		 * off-display by less than half of its on-crtc dimensions.
> +		 */
> +		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> +		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> +	}
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	ret = igt_display_try_commit_atomic(
> +		&data->display,
> +		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
> +		NULL);
> +	if (!ret)
> +		return;
> +
> +	/* Coordinates are logged in the dumped debug log, so only report w/h on
> +	 * failure here. */
> +	igt_assert_f(ret != -ENOSPC,
> +		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
> +		     width, height);
> +
> +	/* Make YUV coordinates a multiple of 2 and retry the math. */
> +	if (is_yuv) {
> +		*src_x &= ~1;
> +		*src_y &= ~1;
> +		*src_w &= ~1;
> +		*src_h &= ~1;
> +		/* To handle 1:1 scaling, clear crtc_w/h too. */
> +		*crtc_w &= ~1;
> +		*crtc_h &= ~1;
> +
> +		if (*crtc_x < 0 && (*crtc_x & 1))
> +			(*crtc_x)++;
> +		else
> +			*crtc_x &= ~1;
> +
> +		/* If negative, round up to 0 instead of down */
> +		if (*crtc_y < 0 && (*crtc_y & 1))
> +			(*crtc_y)++;
> +		else
> +			*crtc_y &= ~1;
> +
> +		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> +				*crtc_h, *crtc_x, *crtc_y, fb);
> +		ret = igt_display_try_commit_atomic(
> +			&data->display,
> +			DRM_MODE_ATOMIC_TEST_ONLY |
> +				DRM_MODE_ATOMIC_ALLOW_MODESET,
> +			NULL);
> +		if (!ret)
> +			return;
> +	}
> +
> +	igt_assert(!ret || allow_scaling);
> +	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> +		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
> +
> +	*crtc_w = *src_w;
> +	*crtc_h = *src_h;
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	igt_display_commit_atomic(&data->display,
> +				  DRM_MODE_ATOMIC_TEST_ONLY |
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET,
> +				  NULL);
> +}
> +
> +static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
> +			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
> +			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
> +			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
> +{
> +	cairo_surface_t *surface;
> +	cairo_surface_t *clipped_surface;
> +	cairo_t *cr;
> +
> +	surface = igt_get_cairo_surface(data->drm_fd, fb);
> +
> +	if (src_x || src_y) {
> +		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> +							     src_w, src_h);
> +
> +		cr = cairo_create(clipped_surface);
> +
> +		cairo_translate(cr, -1. * src_x, -1. * src_y);
> +
> +		cairo_set_source_surface(cr, surface, 0, 0);
> +
> +		cairo_paint(cr);
> +		cairo_surface_flush(clipped_surface);
> +
> +		cairo_destroy(cr);
> +	} else {
> +		clipped_surface = surface;
> +	}
> +
> +	cr = cairo_create(result);
> +
> +	cairo_translate(cr, crtc_x, crtc_y);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
> +	}
> +
> +	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> +	cairo_surface_destroy(clipped_surface);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_pattern_set_filter(cairo_get_source(cr),
> +					 CAIRO_FILTER_BILINEAR);
> +		cairo_pattern_set_extend(cairo_get_source(cr),
> +					 CAIRO_EXTEND_NONE);
> +	}
> +
> +	cairo_paint(cr);
> +	cairo_surface_flush(result);
> +
> +	cairo_destroy(cr);
> +}
> +
> +static void prepare_randomized_plane(chamelium_data_t *data,
> +				     drmModeModeInfo *mode, igt_plane_t *plane,
> +				     struct igt_fb *overlay_fb,
> +				     unsigned int index,
> +				     cairo_surface_t *result_surface,
> +				     bool allow_scaling, bool allow_yuv)
> +{
> +	struct igt_fb pattern_fb;
> +	uint32_t overlay_fb_w, overlay_fb_h;
> +	uint32_t overlay_src_w, overlay_src_h;
> +	uint32_t overlay_src_x, overlay_src_y;
> +	int32_t overlay_crtc_x, overlay_crtc_y;
> +	uint32_t overlay_crtc_w, overlay_crtc_h;
> +	uint32_t format;
> +	uint64_t modifier;
> +	size_t stride;
> +	bool tiled;
> +	int fb_id;
> +
> +	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> +			      &format, &modifier, allow_yuv);
> +
> +	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> +	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
> +		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
> +		  tiled ? "tiled" : "linear");
> +
> +	/* Get a pattern framebuffer for the overlay plane. */
> +	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> +					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
> +			       modifier, &stride);
> +
> +	igt_debug("Plane %d: stride %ld\n", index, stride);
> +
> +	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> +					   modifier, stride);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> +				    &overlay_src_w, &overlay_src_h,
> +				    &overlay_src_x, &overlay_src_y,
> +				    &overlay_crtc_w, &overlay_crtc_h,
> +				    &overlay_crtc_x, &overlay_crtc_y,
> +				    allow_scaling);
> +
> +	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
> +		  overlay_src_h);
> +	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> +		  overlay_src_x, overlay_src_y);
> +	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
> +		  overlay_crtc_h);
> +	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
> +		  overlay_crtc_y);
> +
> +	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> +			 overlay_src_x, overlay_src_y, overlay_crtc_w,
> +			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
> +			 &pattern_fb);
> +
> +	/* Remove the original pattern framebuffer. */
> +	igt_remove_fb(data->drm_fd, &pattern_fb);
> +}
> +
> +static const char test_display_one_mode_desc[] =
> +	"Pick the first mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_one_mode(chamelium_data_t *data,
> +				  struct chamelium_port *port, uint32_t fourcc,
> +				  enum chamelium_check check, int count)
> +{
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	igt_require(igt_plane_has_format_mod(primary, fourcc,
> +					     DRM_FORMAT_MOD_LINEAR));
> +
> +	mode = &connector->modes[0];
> +	if (check == CHAMELIUM_CHECK_ANALOG) {
> +		bool bridge = chamelium_check_analog_bridge(data, port);
> +
> +		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> +	}
> +
> +	do_test_display(data, port, output, mode, fourcc, check, count);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_all_modes_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_all_modes(chamelium_data_t *data,
> +				   struct chamelium_port *port, uint32_t fourcc,
> +				   enum chamelium_check check, int count)
> +{
> +	bool bridge;
> +	int i, count_modes;
> +
> +	if (check == CHAMELIUM_CHECK_ANALOG)
> +		bridge = chamelium_check_analog_bridge(data, port);
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +		igt_require(igt_plane_has_format_mod(primary, fourcc,
> +						     DRM_FORMAT_MOD_LINEAR));
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> +		    prune_vga_mode(data, mode))
> +			continue;
> +
> +		do_test_display(data, port, output, mode, fourcc, check, count);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_frame_dump_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then download the captured frames and compare them "
> +	"bit-by-bit to the sent ones";
> +static void test_display_frame_dump(chamelium_data_t *data,
> +				    struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		struct igt_fb fb;
> +		struct chamelium_frame_dump *frame;
> +		drmModeModeInfo *mode;
> +		drmModeConnector *connector;
> +		int fb_id, j;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		igt_debug("Reading frame dumps from Chamelium...\n");
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> +		for (j = 0; j < 5; j++) {
> +			frame = chamelium_read_captured_frame(data->chamelium,
> +							      j);
> +			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> +			chamelium_destroy_frame_dump(frame);
> +		}
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_aspect_ratio_desc[] =
> +	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> +	"check they include the relevant fields";
> +static void test_display_aspect_ratio(chamelium_data_t *data,
> +				      struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	int fb_id, i;
> +	struct igt_fb fb;
> +	bool found, ok;
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_avi infoframe_avi;
> +	uint8_t vic = 16; /* TODO: test more VICs */
> +	const struct vic_mode *vic_mode;
> +	uint32_t aspect_ratio;
> +	enum infoframe_avi_picture_aspect_ratio frame_ar;
> +
> +	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port,
> +					  IGT_CUSTOM_EDID_ASPECT_RATIO);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	vic_mode = &vic_modes[vic];
> +	aspect_ratio = vic_mode->picture_ar;
> +
> +	found = false;
> +	igt_assert(connector->count_modes > 0);
> +	for (i = 0; i < connector->count_modes; i++) {
> +		mode = &connector->modes[i];
> +
> +		if (vic_mode_matches_drm(vic_mode, mode)) {
> +			found = true;
> +			break;
> +		}
> +	}
> +	igt_assert_f(found,
> +		     "Failed to find mode with the correct aspect ratio\n");
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> +						 CHAMELIUM_INFOFRAME_AVI);
> +	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> +
> +	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> +				 infoframe->payload, infoframe->payload_size);
> +	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> +
> +	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> +
> +	igt_debug("Checking AVI InfoFrame\n");
> +	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> +		  infoframe_avi.picture_aspect_ratio, frame_ar);
> +	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> +		  infoframe_avi.vic, vic);
> +
> +	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> +	igt_assert(infoframe_avi.vic == vic);
> +
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_remove_fb(data->drm_fd, &fb);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_planes_random_desc[] =
> +	"Setup a few overlay planes with random parameters, capture the frame "
> +	"and check it matches the expected output";
> +static void test_display_planes_random(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum chamelium_check check)
> +{
> +	igt_output_t *output;
> +	drmModeModeInfo *mode;
> +	igt_plane_t *primary_plane;
> +	struct igt_fb primary_fb;
> +	struct igt_fb result_fb;
> +	struct igt_fb *overlay_fbs;
> +	igt_crc_t *crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	unsigned int overlay_planes_max = 0;
> +	unsigned int overlay_planes_count;
> +	cairo_surface_t *result_surface;
> +	int captured_frame_count;
> +	bool allow_scaling;
> +	bool allow_yuv;
> +	unsigned int i;
> +	unsigned int fb_id;
> +
> +	switch (check) {
> +	case CHAMELIUM_CHECK_CRC:
> +		allow_scaling = false;
> +		allow_yuv = false;
> +		break;
> +	case CHAMELIUM_CHECK_CHECKERBOARD:
> +		allow_scaling = true;
> +		allow_yuv = true;
> +		break;
> +	default:
> +		igt_assert(false);
> +	}
> +
> +	srand(time(NULL));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Find the connector and pipe. */
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +
> +	mode = igt_output_get_mode(output);
> +
> +	/* Get a framebuffer for the primary plane. */
> +	primary_plane =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary_plane);
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> +	igt_assert(fb_id > 0);
> +
> +	/* Get a framebuffer for the cairo composition result. */
> +	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
> +			      &result_fb);
> +	igt_assert(fb_id > 0);
> +
> +	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> +
> +	/* Paint the primary framebuffer on the result surface. */
> +	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> +			 &primary_fb);
> +
> +	/* Configure the primary plane. */
> +	igt_plane_set_fb(primary_plane, &primary_fb);
> +
> +	overlay_planes_max =
> +		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> +
> +	/* Limit the number of planes to a reasonable scene. */
> +	overlay_planes_max = min(overlay_planes_max, 4u);
> +
> +	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> +	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> +
> +	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> +
> +	for (i = 0; i < overlay_planes_count; i++) {
> +		struct igt_fb *overlay_fb = &overlay_fbs[i];
> +		igt_plane_t *plane = igt_output_get_plane_type_index(
> +			output, DRM_PLANE_TYPE_OVERLAY, i);
> +		igt_assert(plane);
> +
> +		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> +					 result_surface, allow_scaling,
> +					 allow_yuv);
> +	}
> +
> +	cairo_surface_destroy(result_surface);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&result_fb);
> +
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == 1);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
> +						crc, &result_fb, 0);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &result_fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	for (i = 0; i < overlay_planes_count; i++)
> +		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> +
> +	free(overlay_fbs);
> +
> +	igt_remove_fb(data->drm_fd, &primary_fb);
> +	igt_remove_fb(data->drm_fd, &result_fb);
> +}
> +
> +IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-single", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("dp-crc-fast", DisplayPort)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-multiple", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("dp-frame-dump", DisplayPort)
> +			test_display_frame_dump(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-single", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("hdmi-crc-fast", HDMIA)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-multiple", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CRC, 1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-crc-planes-random", HDMIA)
> +			test_display_planes_random(&data, port,
> +						   CHAMELIUM_CHECK_CRC);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (!igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CHECKERBOARD,
> +						1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> +			test_display_planes_random(
> +				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("hdmi-frame-dump", HDMIA)
> +			test_display_frame_dump(&data, port);
> +
> +		igt_describe(test_display_aspect_ratio_desc);
> +		connector_subtest("hdmi-aspect-ratio", HDMIA)
> +			test_display_aspect_ratio(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("vga-frame-dump", VGA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_ANALOG, 1);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
> new file mode 100644
> index 00000000..b9544288
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.c
> @@ -0,0 +1,330 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +
> +void chamelium_init_test(chamelium_data_t *data)
> +{
> +	int i;
> +
> +	/* So fbcon doesn't try to reprobe things itself */
> +	kmstest_set_vt_graphics_mode();
> +
> +	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
> +	igt_display_require(&data->display, data->drm_fd);
> +	igt_require(data->display.is_atomic);
> +
> +	/*
> +	 * XXX: disabling modeset, can be removed when
> +	 * igt_display_require will start doing this for us
> +	 */
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	/* we need to initalize chamelium after igt_display_require */
> +	data->chamelium = chamelium_init(data->drm_fd, &data->display);
> +	igt_require(data->chamelium);
> +
> +	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
> +
> +	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> +		data->edids[i] = chamelium_new_edid(data->chamelium,
> +						    igt_kms_get_custom_edid(i));
> +	}
> +}
> +
> +/* Wait for hotplug and return the remaining time left from timeout */
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> +{
> +	struct timespec start, end;
> +	int elapsed;
> +	bool detected;
> +
> +	igt_assert_eq(igt_gettime(&start), 0);
> +	detected = igt_hotplug_detected(mon, *timeout);
> +	igt_assert_eq(igt_gettime(&end), 0);
> +
> +	elapsed = igt_time_elapsed(&start, &end);
> +	igt_assert_lte(0, elapsed);
> +	*timeout = max(0, *timeout - elapsed);
> +
> +	return detected;
> +}
> +
> +/**
> + * chamelium_wait_for_connector_after_hotplug:
> + *
> + * Waits for the connector attached to @port to have a status of @status after
> + * it's plugged/unplugged.
> + *
> + */
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status)
> +{
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int hotplug_count = 0;
> +
> +	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> +		  chamelium_port_get_name(port),
> +		  kmstest_connector_status_str(status));
> +
> +	while (timeout > 0) {
> +		if (!chamelium_wait_for_hotplug(mon, &timeout))
> +			break;
> +
> +		hotplug_count++;
> +
> +		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> +						port) == status)
> +			return;
> +	}
> +
> +	igt_assert_f(
> +		false,
> +		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> +		chamelium_port_get_name(port),
> +		kmstest_connector_status_str(status),
> +		kmstest_connector_status_str(chamelium_reprobe_connector(
> +			&data->display, data->chamelium, port)),
> +		hotplug_count);
> +}
> +
> +/**
> + * chamelium_port_get_connector:
> + * @data: The Chamelium data instance to use
> + * @port: The chamelium port to prepare its connector
> + * @edid: The chamelium's default EDID has a lot of resolutions, way more then
> + * 		  we need to test. Additionally the default EDID doesn't support
> + *        HDMI audio.
> + *
> + * Makes sure the output display of the connector attached to @port is connected
> + * and ready for use.
> + *
> + * Returns: a pointer to the enabled igt_output_t
> + */
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid)
> +{
> +	igt_display_t *display = &data->display;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	/* The chamelium's default EDID has a lot of resolutions, way more then
> +	 * we need to test. Additionally the default EDID doesn't support HDMI
> +	 * audio.
> +	 */
> +	chamelium_set_edid(data, port, edid);
> +
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_display_reset(display);
> +
> +	output = chamelium_get_output_for_port(data, port);
> +
> +	/* Refresh pipe to update connected status */
> +	igt_output_set_pipe(output, PIPE_NONE);
> +
> +	pipe = chamelium_get_pipe_for_output(display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	return output;
> +}
> +
> +/**
> + * chamelium_enable_output:
> + *
> + * Modesets the connector attached to @port for the assigned @mode and draws the
> + * @fb.
> + *
> + */
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb)
> +{
> +	igt_display_t *display = output->display;
> +	igt_plane_t *primary =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +
> +	igt_assert(primary);
> +
> +	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> +	igt_plane_set_fb(primary, fb);
> +	igt_output_override_mode(output, mode);
> +
> +	/* Clear any color correction values that might be enabled */
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_GAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
> +					       NULL, 0);
> +
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> +		usleep(250000);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +/* Return pipe attached to @outpu.t */
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output)
> +{
> +	enum pipe pipe;
> +
> +	for_each_pipe(display, pipe) {
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			return pipe;
> +		}
> +	}
> +
> +	igt_assert_f(false, "No pipe found for output %s\n",
> +		     igt_output_name(output));
> +}
> +
> +static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
> +					 size_t height, size_t stride,
> +					 size_t block_size)
> +{
> +	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
> +			      0xffffffff };
> +	unsigned i, j;
> +
> +	for (i = 0; i < height; i++)
> +		for (j = 0; j < width; j++)
> +			*(data + i * stride / 4 +
> +			  j) = colors[((j / block_size) + (i / block_size)) % 5];
> +}
> +
> +/**
> + * chamelium_get_pattern_fb:
> + *
> + * Creates an @fb with an xr24 pattern and returns the fb_id.
> + *
> + */
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb)
> +{
> +	int fb_id;
> +	void *ptr;
> +
> +	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> +
> +	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> +			      DRM_FORMAT_MOD_LINEAR, fb);
> +	igt_assert(fb_id > 0);
> +
> +	ptr = igt_fb_map_buffer(fb->fd, fb);
> +	igt_assert(ptr);
> +
> +	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> +				     block_size);
> +	igt_fb_unmap_buffer(fb, ptr);
> +
> +	return fb_id;
> +}
> +
> +/* Generate a simple @fb for the size of @mode. */
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode)
> +{
> +	int fb_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, fb);
> +
> +	igt_assert(fb_id > 0);
> +}
> +
> +/* Returns the first preferred mode for the connector attached to @port. */
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(chamelium, port, false);
> +	drmModeModeInfo mode;
> +	igt_assert(&connector->modes[0] != NULL);
> +	memcpy(&mode, &connector->modes[0], sizeof(mode));
> +	drmModeFreeConnector(connector);
> +	return mode;
> +}
> +
> +/* Returns the igt display output for the connector attached to @port. */
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_output_t *output =
> +		igt_output_from_connector(&data->display, connector);
> +	drmModeFreeConnector(connector);
> +	igt_assert(output != NULL);
> +	return output;
> +}
> +
> +/* Set the EDID of index @edid to Chamelium's @port. */
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid)
> +{
> +	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> +}
> +
> +/**
> + * chamelium_check_analog_bridge:
> + *
> + * Check if the connector associalted to @port is an analog bridge by checking
> + * if it has its own EDID.
> + *
> + */
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +	uint64_t edid_blob_id;
> +	const struct edid *edid;
> +	char edid_vendor[3];
> +
> +	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> +		drmModeFreeConnector(connector);
> +		return false;
> +	}
> +
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob =
> +			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
> +
> +	edid = (const struct edid *)edid_blob->data;
> +	edid_get_mfg(edid, edid_vendor);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +
> +	/* Analog bridges provide their own EDID */
> +	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> +	    edid_vendor[2] != 'T')
> +		return true;
> +
> +	return false;
> +}
> \ No newline at end of file
> diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
> new file mode 100644
> index 00000000..09fa4829
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +
> +#include "igt.h"
> +
> +#define ONLINE_TIMEOUT 20 /* seconds */
> +
> +#define for_each_port(p, port)                                 \
> +	for (p = 0, port = data.ports[p]; p < data.port_count; \
> +	     p++, port = data.ports[p])
> +
> +#define connector_subtest(name__, type__)                           \
> +	igt_subtest(name__)                                         \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +/*
> + * The chamelium data structure is used to store all the information known about
> + * chamelium to run the tests.
> + */
> +typedef struct {
> +	struct chamelium *chamelium;
> +	struct chamelium_port **ports;
> +	igt_display_t display;
> +	int port_count;
> +
> +	int drm_fd;
> +
> +	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> +} chamelium_data_t;
> +
> +void chamelium_init_test(chamelium_data_t *data);
> +
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status);
> +
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid);
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb);
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output);
> +
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb);
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode);
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port);
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port);
> +
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid);
> +
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port);
> +
> +#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
> diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
> new file mode 100644
> index 00000000..8a4e1aba
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_hpd.c
> @@ -0,0 +1,512 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the HPD functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "kms_chamelium_helper.h"
> +
> +#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> +#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> +
> +#define HPD_TOGGLE_COUNT_VGA 5
> +#define HPD_TOGGLE_COUNT_DP_HDMI 15
> +#define HPD_TOGGLE_COUNT_FAST 3
> +
> +enum test_modeset_mode {
> +	TEST_MODESET_ON,
> +	TEST_MODESET_ON_OFF,
> +	TEST_MODESET_OFF,
> +};
> +
> +static void try_suspend_resume_hpd(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   enum igt_suspend_state state,
> +				   enum igt_suspend_test test,
> +				   struct udev_monitor *mon, bool connected)
> +{
> +	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> +						     DRM_MODE_CONNECTED;
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int delay;
> +	int p;
> +
> +	igt_flush_uevents(mon);
> +
> +	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> +
> +	if (port) {
> +		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> +					      !connected);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			port = data->ports[p];
> +			chamelium_schedule_hpd_toggle(data->chamelium, port,
> +						      delay, !connected);
> +		}
> +
> +		port = NULL;
> +	}
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	if (port) {
> +		igt_assert_eq(chamelium_reprobe_connector(
> +				      &data->display, data->chamelium, port),
> +			      target_state);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			drmModeConnection current_state;
> +
> +			port = data->ports[p];
> +			/*
> +			 * There could be as many hotplug events sent by
> +			 * driver as connectors we scheduled an HPD toggle on
> +			 * above, depending on timing. So if we're not seeing
> +			 * the expected connector state try to wait for an HPD
> +			 * event for each connector/port.
> +			 */
> +			current_state = chamelium_reprobe_connector(
> +				&data->display, data->chamelium, port);
> +			if (p > 0 && current_state != target_state) {
> +				igt_assert(chamelium_wait_for_hotplug(
> +					mon, &timeout));
> +				current_state = chamelium_reprobe_connector(
> +					&data->display, data->chamelium, port);
> +			}
> +
> +			igt_assert_eq(current_state, target_state);
> +		}
> +
> +		port = NULL;
> +	}
> +}
> +
> +static const char test_basic_hotplug_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug";
> +static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
> +			 int toggle_count, enum test_modeset_mode modeset_mode)
> +{
> +	int i;
> +	enum pipe pipe;
> +	struct igt_fb fb = { 0 };
> +	drmModeModeInfo mode;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	igt_output_t *output = chamelium_get_output_for_port(data, port);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +
> +	for (i = 0; i < toggle_count; i++) {
> +		igt_flush_uevents(mon);
> +
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF ||
> +		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
> +			if (i == 0) {
> +				/* We can only get mode and pipe once we are
> +				 * connected */
> +				output = chamelium_get_output_for_port(data,
> +								       port);
> +				pipe = chamelium_get_pipe_for_output(
> +					&data->display, output);
> +				mode = chamelium_get_mode_for_port(
> +					data->chamelium, port);
> +				chamelium_create_fb_for_mode(data, &fb, &mode);
> +			}
> +
> +			igt_output_set_pipe(output, pipe);
> +			chamelium_enable_output(data, port, output, &mode, &fb);
> +		}
> +
> +		/* Now check if we get a hotplug from disconnection */
> +		chamelium_unplug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF) {
> +			igt_output_set_pipe(output, PIPE_NONE);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static const char test_hotplug_for_each_pipe_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug for each pipe with valid output";
> +static void test_hotplug_for_each_pipe(chamelium_data_t *data,
> +				       struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	enum pipe pipe;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	/* Disconnect if any port got connected */
> +	chamelium_unplug(data->chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_DISCONNECTED);
> +
> +	for_each_pipe(&data->display, pipe) {
> +		igt_flush_uevents(mon);
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +		output = chamelium_get_output_for_port(data, port);
> +
> +		/* If pipe is valid for output then set it */
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			igt_output_set_pipe(output, pipe);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +
> +		chamelium_unplug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +		igt_flush_uevents(mon);
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_suspend_resume_hpd_desc[] =
> +	"Toggle HPD during suspend, check that uevents are sent and connector "
> +	"status is updated";
> +static void test_suspend_resume_hpd(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_suspend_state state,
> +				    enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_suspend_resume_hpd_common_desc[] =
> +	"Toggle HPD during suspend on all connectors, check that uevents are "
> +	"sent and connector status is updated";
> +static void test_suspend_resume_hpd_common(chamelium_data_t *data,
> +					   enum igt_suspend_state state,
> +					   enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	struct chamelium_port *port;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		port = data->ports[p];
> +		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_without_ddc_desc[] =
> +	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> +static void test_hpd_without_ddc(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +	igt_flush_uevents(mon);
> +
> +	/* Disable the DDC on the connector and make sure we still get a
> +	 * hotplug
> +	 */
> +	chamelium_port_set_ddc_state(data->chamelium, port, false);
> +	chamelium_plug(data->chamelium, port);
> +
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> +						  data->chamelium, port),
> +		      DRM_MODE_CONNECTED);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_storm_detect_desc[] =
> +	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> +	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> +	"storm";
> +static void test_hpd_storm_detect(chamelium_data_t *data,
> +				  struct chamelium_port *port, int width)
> +{
> +	struct udev_monitor *mon;
> +	int count = 0;
> +
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> +
> +	mon = igt_watch_uevents();
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +
> +	/*
> +	 * Polling should have been enabled by the HPD storm at this point,
> +	 * so we should only get at most 1 hotplug event
> +	 */
> +	igt_until_timeout(5)
> +		count += igt_hotplug_detected(mon, 1);
> +	igt_assert_lt(count, 2);
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_hpd_storm_disable_desc[] =
> +	"Disable HPD storm detection, trigger a storm and check the kernel "
> +	"doesn't detect one";
> +static void test_hpd_storm_disable(chamelium_data_t *data,
> +				   struct chamelium_port *port, int width)
> +{
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> +
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("dp-hpd-storm", DisplayPort)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_DP);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_DP);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("hdmi-hpd-storm", HDMIA)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_HDMI);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_HDMI);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-suspend", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-hibernate", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_without_ddc_desc);
> +		connector_subtest("vga-hpd-without-ddc", VGA)
> +			test_hpd_without_ddc(&data, port);
> +	}
> +
> +	igt_describe("Tests that operate on all connectors");
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(data.port_count);
> +		}
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-suspend")
> +			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
> +						       SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-hibernate")
> +			test_suspend_resume_hpd_common(&data,
> +						       SUSPEND_STATE_DISK,
> +						       SUSPEND_TEST_DEVICES);
> +	}
> +
> +	igt_describe(test_hotplug_for_each_pipe_desc);
> +	connector_subtest("vga-hpd-for-each-pipe", VGA)
> +		test_hotplug_for_each_pipe(&data, port);
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
> index 0d307730..6e5cc436 100644
> --- a/tests/intel-ci/blacklist.txt
> +++ b/tests/intel-ci/blacklist.txt
> @@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
>  # is too costly in comparison to the value
>  # provided.
>  ###############################################
> -igt@kms_chamelium@hdmi-.*-planes-random
> +igt@kms_chamelium_frames@hdmi-.*-planes-random
>  ###############################################
>  # Broadcom
>  ###############################################
> diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
> index f57f8ff3..74e2524d 100644
> --- a/tests/intel-ci/fast-feedback.testlist
> +++ b/tests/intel-ci/fast-feedback.testlist
> @@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
>  igt@kms_addfb_basic@unused-offsets
>  igt@kms_addfb_basic@unused-pitches
>  igt@kms_busy@basic
> -igt@kms_chamelium@dp-hpd-fast
> -igt@kms_chamelium@dp-edid-read
> -igt@kms_chamelium@dp-crc-fast
> -igt@kms_chamelium@hdmi-hpd-fast
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@vga-hpd-fast
> -igt@kms_chamelium@vga-edid-read
> +igt@kms_chamelium_hdp@dp-hpd-fast
> +igt@kms_chamelium_edid@dp-edid-read
> +igt@kms_chamelium_frames@dp-crc-fast
> +igt@kms_chamelium_hdp@hdmi-hpd-fast
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_hdp@vga-hpd-fast
> +igt@kms_chamelium_edid@vga-edid-read


A couple of typos here, kms_chamelium_hdp written, kms_chamelium_hpd intended.


-- 
Petri Latvala



>  igt@kms_prop_blob@basic
>  igt@kms_cursor_legacy@basic-busy-flip-before-cursor
>  igt@kms_cursor_legacy@basic-flip-after-cursor
> @@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
>  igt@i915_suspend@basic-s3-without-i915
>  igt@gem_exec_suspend@basic-s0
>  igt@gem_exec_suspend@basic-s3
> -igt@kms_chamelium@common-hpd-after-suspend
> +igt@kms_chamelium_hpd@common-hpd-after-suspend
>  igt@kms_pipe_crc_basic@suspend-read-crc
> diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
> index f0ae30e3..f9242232 100644
> --- a/tests/kms_color_helper.h
> +++ b/tests/kms_color_helper.h
> @@ -27,7 +27,7 @@
>  
>  /*
>   * This header is for code that is shared between kms_color.c and
> - * kms_color_chamelium.c. Reusability elsewhere can be questionable.
> + * kms_chamelium_color.c. Reusability elsewhere can be questionable.
>   */
>  
>  #include <math.h>
> diff --git a/tests/meson.build b/tests/meson.build
> index 5c052e73..b52399d5 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -260,7 +260,10 @@ msm_progs = [
>  ]
>  
>  chamelium_progs = [
> -	'kms_chamelium',
> +	'kms_chamelium_audio',
> +	'kms_chamelium_edid',
> +	'kms_chamelium_frames',
> +	'kms_chamelium_hpd',
>  ]
>  
>  test_deps = [ igt_deps ]
> @@ -309,7 +312,8 @@ endforeach
>  if chamelium.found()
>  	foreach prog : chamelium_progs
>  		test_executables += executable(prog,
> -				 join_paths('chamelium', prog + '.c'),
> +				 [join_paths('chamelium', prog + '.c'), 
> +				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
>  				 dependencies : test_deps,
>  				 install_dir : libexecdir,
>  				 install_rpath : libexecdir_rpathdir,
> @@ -436,13 +440,13 @@ test_executables += executable('kms_color',
>  test_list += 'kms_color'
>  
>  if chamelium.found()
> -       test_executables += executable('kms_color_chamelium',
> -                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
> +       test_executables += executable('kms_chamelium_color',
> +                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
>                               dependencies : test_deps + [ chamelium ],
>                               install_dir : libexecdir,
>                               install_rpath : libexecdir_rpathdir,
>                               install : true)
> -       test_list += 'kms_color_chamelium'
> +       test_list += 'kms_chamelium_color'
>  endif
>  
>  test_executables += executable('sw_sync', 'sw_sync.c',
> diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
> index dd45d12a..a5521021 100644
> --- a/tests/vc4_ci/vc4-chamelium-fast.testlist
> +++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
> @@ -1,14 +1,14 @@
> -igt@kms_chamelium@hdmi-crc-abgr8888
> -igt@kms_chamelium@hdmi-crc-argb1555
> -igt@kms_chamelium@hdmi-crc-argb8888
> -igt@kms_chamelium@hdmi-crc-bgr565
> -igt@kms_chamelium@hdmi-crc-bgr888
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@hdmi-crc-rgb565
> -igt@kms_chamelium@hdmi-crc-rgb888
> -igt@kms_chamelium@hdmi-crc-xbgr8888
> -igt@kms_chamelium@hdmi-crc-xrgb1555
> -igt@kms_chamelium@hdmi-crc-xrgb8888
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-hpd
> -igt@kms_chamelium@hdmi-hpd-fast
> +igt@kms_chamelium_frames@hdmi-crc-abgr8888
> +igt@kms_chamelium_frames@hdmi-crc-argb1555
> +igt@kms_chamelium_frames@hdmi-crc-argb8888
> +igt@kms_chamelium_frames@hdmi-crc-bgr565
> +igt@kms_chamelium_frames@hdmi-crc-bgr888
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_frames@hdmi-crc-rgb565
> +igt@kms_chamelium_frames@hdmi-crc-rgb888
> +igt@kms_chamelium_frames@hdmi-crc-xbgr8888
> +igt@kms_chamelium_frames@hdmi-crc-xrgb1555
> +igt@kms_chamelium_frames@hdmi-crc-xrgb8888
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_hpd@hdmi-hpd
> +igt@kms_chamelium_hpd@hdmi-hpd-fast
> -- 
> 2.38.1.584.g0f3c55d4c2-goog
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] [PATCH v2] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (3 preceding siblings ...)
  2022-12-01 14:49 ` [igt-dev] [PATCH] " Petri Latvala
@ 2022-12-01 16:29 ` Mark Yacoub
  2022-12-02  9:48   ` Petri Latvala
  2022-12-06 18:56   ` [igt-dev] [PATCH v3] " Mark Yacoub
  2022-12-01 18:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2) Patchwork
                   ` (8 subsequent siblings)
  13 siblings, 2 replies; 25+ messages in thread
From: Mark Yacoub @ 2022-12-01 16:29 UTC (permalink / raw)
  To: igt-dev
  Cc: robdclark, vsuley, petri.latvala, ihf, amstan, kalin, seanpaul,
	matthewtlam, markyacoub, khaled.almahallawy

[Why]
kms_chamelium tests file has grown so much and became a bit big to
manage.
Splitting specific tests like we do for kms_ tests into separate files
puts logically related functionalities into the same place so tests are
more clear.

[How]
Split kms_chamelium into 4 different tests, each testing something
specific. The tests are:
1. kms_chamelium_audio
2. kms_chamelium_edid
3. kms_chamelium_frames
4. kms_chamelium_hpd
5. kms_chamelium_color which used to be kms_color_chamelium but renamed
   for consistency.

All common code lives in kms_chamelium_helper and the function names
have a chamelium_ prefix.

v1:
Fix typo and add missing #include

Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
---
 docs/chamelium.txt                            |    2 +-
 lib/igt_edid.h                                |    1 +
 lib/igt_eld.h                                 |    1 +
 lib/monitor_edids/monitor_edids_helper.c      |    2 +-
 tests/chamelium/kms_chamelium.c               | 3132 -----------------
 tests/chamelium/kms_chamelium_audio.c         |  858 +++++
 ...olor_chamelium.c => kms_chamelium_color.c} |    0
 tests/chamelium/kms_chamelium_edid.c          |  534 +++
 tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
 tests/chamelium/kms_chamelium_helper.c        |  330 ++
 tests/chamelium/kms_chamelium_helper.h        |   74 +
 tests/chamelium/kms_chamelium_hpd.c           |  512 +++
 tests/intel-ci/blacklist.txt                  |    2 +-
 tests/intel-ci/fast-feedback.testlist         |   18 +-
 tests/kms_color_helper.h                      |    2 +-
 tests/meson.build                             |   14 +-
 tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
 17 files changed, 3431 insertions(+), 3164 deletions(-)
 delete mode 100644 tests/chamelium/kms_chamelium.c
 create mode 100644 tests/chamelium/kms_chamelium_audio.c
 rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
 create mode 100644 tests/chamelium/kms_chamelium_edid.c
 create mode 100644 tests/chamelium/kms_chamelium_frames.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.h
 create mode 100644 tests/chamelium/kms_chamelium_hpd.c

diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index c4c22468..f82c8b0c 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -241,7 +241,7 @@ Current Support in IGT
 
 Support for the Chamelium platform in IGT is found in the following places:
 * lib/igt_chamelium.c: library with Chamelium-related helpers
-* tests/kms_chamelium.c: sub-tests using the Chamelium
+* tests/kms_chamelium_*.c: sub-tests using the Chamelium
 
 As of early April 2019, the following features are tested by IGT:
 * Pixel-by-pixel frame integrity tests for DP and HDMI
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 477f16c2..85a9ef5e 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdint.h>
+#include <stddef.h>
 
 #include <xf86drmMode.h>
 
diff --git a/lib/igt_eld.h b/lib/igt_eld.h
index 30d7012d..1a46b6d2 100644
--- a/lib/igt_eld.h
+++ b/lib/igt_eld.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stddef.h>
 
 #include "igt_edid.h"
 
diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
index 41f199bd..1cbf1c22 100644
--- a/lib/monitor_edids/monitor_edids_helper.c
+++ b/lib/monitor_edids/monitor_edids_helper.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 /*
  * A helper library for parsing and making use of real EDID data from monitors
  * and make them compatible with IGT and Chamelium.
diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
deleted file mode 100644
index 3c4b4d75..00000000
--- a/tests/chamelium/kms_chamelium.c
+++ /dev/null
@@ -1,3132 +0,0 @@
-/*
- * Copyright © 2016 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Lyude Paul <lyude@redhat.com>
- */
-
-#include "config.h"
-#include "igt.h"
-#include "igt_vc4.h"
-#include "igt_edid.h"
-#include "igt_eld.h"
-#include "igt_infoframe.h"
-#include "monitor_edids/dp_edids.h"
-#include "monitor_edids/hdmi_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,
-	TEST_MODESET_ON_OFF,
-	TEST_MODESET_OFF,
-};
-
-typedef struct {
-	struct chamelium *chamelium;
-	struct chamelium_port **ports;
-	igt_display_t display;
-	int port_count;
-
-	int drm_fd;
-
-	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
-} data_t;
-
-#define ONLINE_TIMEOUT 20 /* seconds */
-
-#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
-#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
-
-#define HPD_TOGGLE_COUNT_VGA 5
-#define HPD_TOGGLE_COUNT_DP_HDMI 15
-#define HPD_TOGGLE_COUNT_FAST 3
-
-static void
-get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
-{
-	drmModeConnector *connector;
-	uint64_t link_status;
-	drmModePropertyPtr prop;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		connector = chamelium_port_get_connector(data->chamelium,
-							 data->ports[p], false);
-
-		igt_assert(kmstest_get_property(data->drm_fd,
-						connector->connector_id,
-						DRM_MODE_OBJECT_CONNECTOR,
-						"link-status", NULL,
-						&link_status, &prop));
-
-		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
-
-		drmModeFreeProperty(prop);
-		drmModeFreeConnector(connector);
-	}
-}
-
-/* Wait for hotplug and return the remaining time left from timeout */
-static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
-{
-	struct timespec start, end;
-	int elapsed;
-	bool detected;
-
-	igt_assert_eq(igt_gettime(&start), 0);
-	detected = igt_hotplug_detected(mon, *timeout);
-	igt_assert_eq(igt_gettime(&end), 0);
-
-	elapsed = igt_time_elapsed(&start, &end);
-	igt_assert_lte(0, elapsed);
-	*timeout = max(0, *timeout - elapsed);
-
-	return detected;
-}
-
-static void
-wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
-				 struct chamelium_port *port,
-				 drmModeConnection status)
-{
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int hotplug_count = 0;
-
-	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
-			  chamelium_port_get_name(port),
-			  kmstest_connector_status_str(status));
-
-	while (timeout > 0) {
-		if (!wait_for_hotplug(mon, &timeout))
-			break;
-
-		hotplug_count++;
-
-		if (chamelium_reprobe_connector(&data->display, data->chamelium,
-						port) == status)
-			return;
-	}
-
-	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
-			    chamelium_port_get_name(port),
-			    kmstest_connector_status_str(status),
-			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
-}
-
-
-static int chamelium_vga_modes[][2] = {
-	{ 1600, 1200 },
-	{ 1920, 1200 },
-	{ 1920, 1080 },
-	{ 1680, 1050 },
-	{ 1280, 1024 },
-	{ 1280, 960 },
-	{ 1440, 900 },
-	{ 1280, 800 },
-	{ 1024, 768 },
-	{ 1360, 768 },
-	{ 1280, 720 },
-	{ 800, 600 },
-	{ 640, 480 },
-	{ -1, -1 },
-};
-
-static bool
-prune_vga_mode(data_t *data, drmModeModeInfo *mode)
-{
-	int i = 0;
-
-	while (chamelium_vga_modes[i][0] != -1) {
-		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
-		    mode->vdisplay == chamelium_vga_modes[i][1])
-			return false;
-
-		i++;
-	}
-
-	return true;
-}
-
-static bool
-check_analog_bridge(data_t *data, struct chamelium_port *port)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-	uint64_t edid_blob_id;
-	const struct edid *edid;
-	char edid_vendor[3];
-
-	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
-		drmModeFreeConnector(connector);
-		return false;
-	}
-
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	edid = (const struct edid *) edid_blob->data;
-	edid_get_mfg(edid, edid_vendor);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-
-	/* Analog bridges provide their own EDID */
-	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
-	    edid_vendor[2] != 'T')
-		return true;
-
-	return false;
-}
-
-static void chamelium_paint_xr24_pattern(uint32_t *data,
-					 size_t width, size_t height,
-					 size_t stride, size_t block_size)
-{
-	uint32_t colors[] = { 0xff000000,
-			      0xffff0000,
-			      0xff00ff00,
-			      0xff0000ff,
-			      0xffffffff };
-	unsigned i, j;
-
-	for (i = 0; i < height; i++)
-		for (j = 0; j < width; j++)
-			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
-}
-
-static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
-				    uint32_t fourcc, size_t block_size,
-				    struct igt_fb *fb)
-{
-	int fb_id;
-	void *ptr;
-
-	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
-
-	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
-			      DRM_FORMAT_MOD_LINEAR, fb);
-	igt_assert(fb_id > 0);
-
-	ptr = igt_fb_map_buffer(fb->fd, fb);
-	igt_assert(ptr);
-
-	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
-				     block_size);
-	igt_fb_unmap_buffer(fb, ptr);
-
-	return fb_id;
-}
-
-static void
-enable_output(data_t *data,
-	      struct chamelium_port *port,
-	      igt_output_t *output,
-	      drmModeModeInfo *mode,
-	      struct igt_fb *fb)
-{
-	igt_display_t *display = output->display;
-	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-
-	igt_assert(primary);
-
-	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
-	igt_plane_set_fb(primary, fb);
-	igt_output_override_mode(output, mode);
-
-	/* Clear any color correction values that might be enabled */
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
-
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
-		usleep(250000);
-
-	drmModeFreeConnector(connector);
-}
-
-static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
-{
-	enum pipe pipe;
-
-	for_each_pipe(display, pipe) {
-		if (igt_pipe_connector_valid(pipe, output)) {
-			return pipe;
-		}
-	}
-
-	igt_assert_f(false, "No pipe found for output %s\n",
-		     igt_output_name(output));
-}
-
-static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
-{
-	int fb_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, fb);
-
-	igt_assert(fb_id > 0);
-}
-
-static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
-								   port, false);
-	drmModeModeInfo mode;
-	igt_assert(&connector->modes[0] != NULL);
-	memcpy(&mode, &connector->modes[0], sizeof(mode));
-	drmModeFreeConnector(connector);
-	return mode;
-}
-
-static igt_output_t *get_output_for_port(data_t *data,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector =
-		chamelium_port_get_connector(data->chamelium, port, true);
-	igt_output_t *output = igt_output_from_connector(&data->display,
-							 connector);
-	drmModeFreeConnector(connector);
-	igt_assert(output != NULL);
-	return output;
-}
-
-static const char test_hotplug_for_each_pipe_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug for each pipe with valid output";
-static void
-test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	enum pipe pipe;
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	chamelium_reset_state(&data->display,
-			      data->chamelium,
-			      port,
-			      data->ports,
-			      data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	/* Disconnect if any port got connected */
-	chamelium_unplug(data->chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port,
-			DRM_MODE_DISCONNECTED);
-
-	for_each_pipe(&data->display, pipe) {
-		igt_flush_uevents(mon);
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-		output = get_output_for_port(data, port);
-
-		/* If pipe is valid for output then set it */
-		if (igt_pipe_connector_valid(pipe, output)) {
-			igt_output_set_pipe(output, pipe);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-
-		chamelium_unplug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_DISCONNECTED);
-		igt_flush_uevents(mon);
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_basic_hotplug_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug";
-static void
-test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
-	     enum test_modeset_mode modeset_mode)
-{
-	int i;
-	enum pipe pipe;
-	struct igt_fb fb = {0};
-	drmModeModeInfo mode;
-	struct udev_monitor *mon = igt_watch_uevents();
-	igt_output_t *output = get_output_for_port(data, port);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-
-	for (i = 0; i < toggle_count; i++) {
-		igt_flush_uevents(mon);
-
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF ||
-		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
-			if (i == 0) {
-				/* We can only get mode and pipe once we are connected */
-				output = get_output_for_port(data, port);
-				pipe = get_pipe_for_output(&data->display, output);
-				mode = get_mode_for_port(data->chamelium, port);
-				create_fb_for_mode(data, &fb, &mode);
-			}
-
-			igt_output_set_pipe(output, pipe);
-			enable_output(data, port, output, &mode, &fb);
-		}
-
-		/* Now check if we get a hotplug from disconnection */
-		chamelium_unplug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_DISCONNECTED);
-
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF) {
-			igt_output_set_pipe(output, PIPE_NONE);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static void set_edid(data_t *data, struct chamelium_port *port,
-		     enum igt_custom_edid_type edid)
-{
-	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
-}
-
-static const char igt_custom_edid_type_read_desc[] =
-	"Make sure the EDID exposed by KMS is the same as the screen's";
-static void
-igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector;
-	size_t raw_edid_size;
-	const struct edid *raw_edid;
-	uint64_t edid_blob_id;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_skip_on(check_analog_bridge(data, port));
-
-	connector = chamelium_port_get_connector(data->chamelium, port, true);
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob_id != 0);
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
-	raw_edid_size = edid_get_size(raw_edid);
-	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-}
-
-static void
-try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-		       enum igt_suspend_state state, enum igt_suspend_test test,
-		       struct udev_monitor *mon, bool connected)
-{
-	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
-						     DRM_MODE_CONNECTED;
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int delay;
-	int p;
-
-	igt_flush_uevents(mon);
-
-	delay = igt_get_autoresume_delay(state) * 1000 / 2;
-
-	if (port) {
-		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
-					      !connected);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			port = data->ports[p];
-			chamelium_schedule_hpd_toggle(data->chamelium, port,
-						      delay, !connected);
-		}
-
-		port = NULL;
-	}
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(wait_for_hotplug(mon, &timeout));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	if (port) {
-		igt_assert_eq(chamelium_reprobe_connector(&data->display,
-							  data->chamelium,
-							  port),
-							  target_state);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			drmModeConnection current_state;
-
-			port = data->ports[p];
-			/*
-			 * There could be as many hotplug events sent by
-			 * driver as connectors we scheduled an HPD toggle on
-			 * above, depending on timing. So if we're not seeing
-			 * the expected connector state try to wait for an HPD
-			 * event for each connector/port.
-			 */
-			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			if (p > 0 && current_state != target_state) {
-				igt_assert(wait_for_hotplug(mon, &timeout));
-				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			}
-
-			igt_assert_eq(current_state, target_state);
-		}
-
-		port = NULL;
-	}
-}
-
-static const char test_suspend_resume_hpd_desc[] =
-	"Toggle HPD during suspend, check that uevents are sent and connector "
-	"status is updated";
-static void
-test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-			enum igt_suspend_state state,
-			enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_hpd_common_desc[] =
-	"Toggle HPD during suspend on all connectors, check that uevents are "
-	"sent and connector status is updated";
-static void
-test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
-			       enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	struct chamelium_port *port;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		port = data->ports[p];
-		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_edid_change_desc[] =
-	"Simulate a screen being unplugged and another screen being plugged "
-	"during suspend, check that a uevent is sent and connector status is "
-	"updated";
-static void
-test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
-				enum igt_suspend_state state,
-				enum igt_suspend_test test,
-				enum igt_custom_edid_type edid,
-				enum igt_custom_edid_type alt_edid)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	bool link_status_failed[2][data->port_count];
-	int p;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Catch the event and flush all remaining ones. */
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_flush_uevents(mon);
-
-	/* First plug in the port */
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	/*
-	 * Change the edid before we suspend. On resume, the machine should
-	 * notice the EDID change and fire a hotplug event.
-	 */
-	set_edid(data, port, alt_edid);
-
-	get_connectors_link_status_failed(data, link_status_failed[0]);
-
-	igt_flush_uevents(mon);
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	get_connectors_link_status_failed(data, link_status_failed[1]);
-
-	for (p = 0; p < data->port_count; p++)
-		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
-}
-
-static igt_output_t *
-prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	/* The chamelium's default EDID has a lot of resolutions, way more then
-	 * we need to test. Additionally the default EDID doesn't support HDMI
-	 * audio.
-	 */
-	set_edid(data, port, edid);
-
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_display_reset(display);
-
-	output = get_output_for_port(data, port);
-
-	/* Refresh pipe to update connected status */
-	igt_output_set_pipe(output, PIPE_NONE);
-
-	pipe = get_pipe_for_output(display, output);
-	igt_output_set_pipe(output, pipe);
-
-	return output;
-}
-
-static void do_test_display(data_t *data, struct chamelium_port *port,
-			    igt_output_t *output, drmModeModeInfo *mode,
-			    uint32_t fourcc, enum chamelium_check check,
-			    int count)
-{
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb frame_fb, fb;
-	int i, fb_id, captured_frame_count;
-	int frame_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &fb);
-	igt_assert(fb_id > 0);
-
-	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
-				  DRM_FORMAT_MOD_LINEAR);
-	igt_assert(frame_id > 0);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-
-	enable_output(data, port, output, mode, &frame_fb);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		igt_crc_t *expected_crc;
-		igt_crc_t *crc;
-
-		/* We want to keep the display running for a little bit, since
-		 * there's always the potential the driver isn't able to keep
-		 * the display running properly for very long
-		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == count);
-
-		igt_debug("Captured %d frames\n", captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		for (i = 0; i < captured_frame_count; i++)
-			chamelium_assert_crc_eq_or_dump(data->chamelium,
-							expected_crc, &crc[i],
-							&fb, i);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_ANALOG ||
-		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		igt_assert(count == 1);
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-
-		if (check == CHAMELIUM_CHECK_ANALOG)
-			chamelium_crop_analog_frame(dump, mode->hdisplay,
-						    mode->vdisplay);
-
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	igt_remove_fb(data->drm_fd, &frame_fb);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static const char test_display_one_mode_desc[] =
-	"Pick the first mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_one_mode(data_t *data, struct chamelium_port *port,
-				  uint32_t fourcc, enum chamelium_check check,
-				  int count)
-{
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	igt_output_t *output;
-	igt_plane_t *primary;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
-
-	mode = &connector->modes[0];
-	if (check == CHAMELIUM_CHECK_ANALOG) {
-		bool bridge = check_analog_bridge(data, port);
-
-		igt_assert(!(bridge && prune_vga_mode(data, mode)));
-	}
-
-	do_test_display(data, port, output, mode, fourcc, check, count);
-
-	drmModeFreeConnector(connector);
-}
-
-static const char test_display_all_modes_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_all_modes(data_t *data, struct chamelium_port *port,
-				   uint32_t fourcc, enum chamelium_check check,
-				   int count)
-{
-	bool bridge;
-	int i, count_modes;
-
-	if (check == CHAMELIUM_CHECK_ANALOG)
-		bridge = check_analog_bridge(data, port);
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-		igt_require(igt_plane_has_format_mod(primary, fourcc,
-			    DRM_FORMAT_MOD_LINEAR));
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
-		    prune_vga_mode(data, mode))
-			continue;
-
-		do_test_display(data, port, output, mode, fourcc, check,
-				count);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-static const char test_display_frame_dump_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then download the captured frames and compare them "
-	"bit-by-bit to the sent ones";
-static void
-test_display_frame_dump(data_t *data, struct chamelium_port *port)
-{
-
-	int i, count_modes;
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		struct igt_fb fb;
-		struct chamelium_frame_dump *frame;
-		drmModeModeInfo *mode;
-		drmModeConnector *connector;
-		int fb_id, j;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Reading frame dumps from Chamelium...\n");
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
-		for (j = 0; j < 5; j++) {
-			frame = chamelium_read_captured_frame(data->chamelium,
-							      j);
-			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
-			chamelium_destroy_frame_dump(frame);
-		}
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
-
-static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
-		       drmModeModeInfo *mode)
-{
-	struct chamelium_video_params video_params = {0};
-	double mode_clock;
-	int mode_hsync_offset, mode_vsync_offset;
-	int mode_hsync_width, mode_vsync_width;
-	int mode_hsync_polarity, mode_vsync_polarity;
-
-	chamelium_port_get_video_params(chamelium, port, &video_params);
-
-	mode_clock = (double) mode->clock / 1000;
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
-		/* this is what chamelium understands as offsets for DP */
-		mode_hsync_offset = mode->htotal - mode->hsync_start;
-		mode_vsync_offset = mode->vtotal - mode->vsync_start;
-	} else {
-		/* and this is what they are for other connectors */
-		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
-		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
-	}
-
-	mode_hsync_width = mode->hsync_end - mode->hsync_start;
-	mode_vsync_width = mode->vsync_end - mode->vsync_start;
-
-	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-
-	igt_debug("Checking video mode:\n");
-	igt_debug("clock: got %f, expected %f ± %f%%\n",
-		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
-	igt_debug("hactive: got %d, expected %d\n",
-		  video_params.hactive, mode->hdisplay);
-	igt_debug("vactive: got %d, expected %d\n",
-		  video_params.vactive, mode->vdisplay);
-	igt_debug("hsync_offset: got %d, expected %d\n",
-		  video_params.hsync_offset, mode_hsync_offset);
-	igt_debug("vsync_offset: got %d, expected %d\n",
-		  video_params.vsync_offset, mode_vsync_offset);
-	igt_debug("htotal: got %d, expected %d\n",
-		  video_params.htotal, mode->htotal);
-	igt_debug("vtotal: got %d, expected %d\n",
-		  video_params.vtotal, mode->vtotal);
-	igt_debug("hsync_width: got %d, expected %d\n",
-		  video_params.hsync_width, mode_hsync_width);
-	igt_debug("vsync_width: got %d, expected %d\n",
-		  video_params.vsync_width, mode_vsync_width);
-	igt_debug("hsync_polarity: got %d, expected %d\n",
-		  video_params.hsync_polarity, mode_hsync_polarity);
-	igt_debug("vsync_polarity: got %d, expected %d\n",
-		  video_params.vsync_polarity, mode_vsync_polarity);
-
-	if (!isnan(video_params.clock)) {
-		igt_assert(video_params.clock >
-			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
-		igt_assert(video_params.clock <
-			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
-	}
-	igt_assert(video_params.hactive == mode->hdisplay);
-	igt_assert(video_params.vactive == mode->vdisplay);
-	igt_assert(video_params.hsync_offset == mode_hsync_offset);
-	igt_assert(video_params.vsync_offset == mode_vsync_offset);
-	igt_assert(video_params.htotal == mode->htotal);
-	igt_assert(video_params.vtotal == mode->vtotal);
-	igt_assert(video_params.hsync_width == mode_hsync_width);
-	igt_assert(video_params.vsync_width == mode_vsync_width);
-	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
-	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
-}
-
-static const char test_mode_timings_desc[] =
-	"For each mode of the IGT base EDID, perform a modeset and check the "
-	"mode detected by the Chamelium receiver matches the mode we set";
-static void test_mode_timings(data_t *data, struct chamelium_port *port)
-{
-	int i, count_modes;
-
-	i = 0;
-	igt_require(chamelium_supports_get_video_params(data->chamelium));
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-		int fb_id;
-		struct igt_fb fb;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port, false);
-		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		/* Trigger the FSM */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
-
-		check_mode(data->chamelium, port, mode);
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-struct vic_mode {
-	int hactive, vactive;
-	int vrefresh; /* Hz */
-	uint32_t picture_ar;
-};
-
-/* Maps Video Identification Codes to a mode */
-static const struct vic_mode vic_modes[] = {
-	[16] = {
-		.hactive = 1920,
-		.vactive = 1080,
-		.vrefresh = 60,
-		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
-	},
-};
-
-/* Maps aspect ratios to their mode flag */
-static const uint32_t mode_ar_flags[] = {
-	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
-};
-
-static enum infoframe_avi_picture_aspect_ratio
-get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
-{
-	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
-	switch (aspect_ratio) {
-	case DRM_MODE_PICTURE_ASPECT_4_3:
-		return INFOFRAME_AVI_PIC_AR_4_3;
-	case DRM_MODE_PICTURE_ASPECT_16_9:
-		return INFOFRAME_AVI_PIC_AR_16_9;
-	default:
-		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
-	}
-}
-
-static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
-				 drmModeModeInfo *drm_mode)
-{
-	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
-
-	return vic_mode->hactive == drm_mode->hdisplay &&
-	       vic_mode->vactive == drm_mode->vdisplay &&
-	       vic_mode->vrefresh == drm_mode->vrefresh &&
-	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
-}
-
-static const char test_display_aspect_ratio_desc[] =
-	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
-	"check they include the relevant fields";
-static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	int fb_id, i;
-	struct igt_fb fb;
-	bool found, ok;
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_avi infoframe_avi;
-	uint8_t vic = 16; /* TODO: test more VICs */
-	const struct vic_mode *vic_mode;
-	uint32_t aspect_ratio;
-	enum infoframe_avi_picture_aspect_ratio frame_ar;
-
-	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	vic_mode = &vic_modes[vic];
-	aspect_ratio = vic_mode->picture_ar;
-
-	found = false;
-	igt_assert(connector->count_modes > 0);
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-
-		if (vic_mode_matches_drm(vic_mode, mode)) {
-			found = true;
-			break;
-		}
-	}
-	igt_assert_f(found,
-		     "Failed to find mode with the correct aspect ratio\n");
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
-						 CHAMELIUM_INFOFRAME_AVI);
-	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
-
-	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
-				 infoframe->payload, infoframe->payload_size);
-	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
-
-	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
-
-	igt_debug("Checking AVI InfoFrame\n");
-	igt_debug("Picture aspect ratio: got %d, expected %d\n",
-		  infoframe_avi.picture_aspect_ratio, frame_ar);
-	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
-		  infoframe_avi.vic, vic);
-
-	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
-	igt_assert(infoframe_avi.vic == vic);
-
-	chamelium_infoframe_destroy(infoframe);
-	igt_remove_fb(data->drm_fd, &fb);
-	drmModeFreeConnector(connector);
-}
-
-
-/* Playback parameters control the audio signal we synthesize and send */
-#define PLAYBACK_CHANNELS 2
-#define PLAYBACK_SAMPLES 1024
-
-/* Capture paremeters control the audio signal we receive */
-#define CAPTURE_SAMPLES 2048
-
-#define AUDIO_TIMEOUT 2000 /* ms */
-/* A streak of 3 gives confidence that the signal is good. */
-#define MIN_STREAK 3
-
-#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
-#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
-#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
-
-/* TODO: enable >48KHz rates, these are not reliable */
-static int test_sampling_rates[] = {
-	32000,
-	44100,
-	48000,
-	/* 88200, */
-	/* 96000, */
-	/* 176400, */
-	/* 192000, */
-};
-
-static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
-
-/* Test frequencies (Hz): a sine signal will be generated for each.
- *
- * Depending on the sampling rate chosen, it might not be possible to properly
- * detect the generated sine (see Nyquist–Shannon sampling theorem).
- * Frequencies that can't be reliably detected will be automatically pruned in
- * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
- * tested with a 192KHz sampling rate.
- */
-static int test_frequencies[] = {
-	300,
-	600,
-	1200,
-	10000,
-	80000,
-};
-
-static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
-
-static const snd_pcm_format_t test_formats[] = {
-	SND_PCM_FORMAT_S16_LE,
-	SND_PCM_FORMAT_S24_LE,
-	SND_PCM_FORMAT_S32_LE,
-};
-
-static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
-
-struct audio_state {
-	struct alsa *alsa;
-	struct chamelium *chamelium;
-	struct chamelium_port *port;
-	struct chamelium_stream *stream;
-
-	/* The capture format is only available after capture has started. */
-	struct {
-		snd_pcm_format_t format;
-		int channels;
-		int rate;
-	} playback, capture;
-
-	char *name;
-	struct audio_signal *signal; /* for frequencies test only */
-	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	size_t recv_pages;
-	int msec;
-
-	int dump_fd;
-	char *dump_path;
-
-	pthread_t thread;
-	atomic_bool run;
-	atomic_bool positive; /* for pulse test only */
-};
-
-static void audio_state_init(struct audio_state *state, data_t *data,
-			     struct alsa *alsa, struct chamelium_port *port,
-			     snd_pcm_format_t format, int channels, int rate)
-{
-	memset(state, 0, sizeof(*state));
-	state->dump_fd = -1;
-
-	state->alsa = alsa;
-	state->chamelium = data->chamelium;
-	state->port = port;
-
-	state->playback.format = format;
-	state->playback.channels = channels;
-	state->playback.rate = rate;
-
-	alsa_configure_output(alsa, format, channels, rate);
-
-	state->stream = chamelium_stream_init();
-	igt_assert_f(state->stream,
-		     "Failed to initialize Chamelium stream client\n");
-}
-
-static void audio_state_fini(struct audio_state *state)
-{
-	chamelium_stream_deinit(state->stream);
-	free(state->name);
-}
-
-static void *run_audio_thread(void *data)
-{
-	struct alsa *alsa = data;
-
-	alsa_run(alsa, -1);
-	return NULL;
-}
-
-static void audio_state_start(struct audio_state *state, const char *name)
-{
-	int ret;
-	bool ok;
-	size_t i, j;
-	enum chamelium_stream_realtime_mode stream_mode;
-	char dump_suffix[64];
-
-	free(state->name);
-	state->name = strdup(name);
-	state->recv_pages = 0;
-	state->msec = 0;
-
-	igt_debug("Starting %s test with playback format %s, "
-		  "sampling rate %d Hz and %d channels\n",
-		  name, snd_pcm_format_name(state->playback.format),
-		  state->playback.rate, state->playback.channels);
-
-	chamelium_start_capturing_audio(state->chamelium, state->port, false);
-
-	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
-	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
-	igt_assert_f(ok, "Failed to start streaming audio capture\n");
-
-	/* Start playing audio */
-	state->run = true;
-	ret = pthread_create(&state->thread, NULL,
-			     run_audio_thread, state->alsa);
-	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
-
-	/* The Chamelium device only supports this PCM format. */
-	state->capture.format = SND_PCM_FORMAT_S32_LE;
-
-	/* Only after we've started playing audio, we can retrieve the capture
-	 * format used by the Chamelium device. */
-	chamelium_get_audio_format(state->chamelium, state->port,
-				   &state->capture.rate,
-				   &state->capture.channels);
-	if (state->capture.rate == 0) {
-		igt_debug("Audio receiver doesn't indicate the capture "
-			 "sampling rate, assuming it's %d Hz\n",
-			 state->playback.rate);
-		state->capture.rate = state->playback.rate;
-	}
-
-	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
-					    state->channel_mapping);
-	/* Make sure we can capture all channels we send. */
-	for (i = 0; i < state->playback.channels; i++) {
-		ok = false;
-		for (j = 0; j < state->capture.channels; j++) {
-			if (state->channel_mapping[j] == i) {
-				ok = true;
-				break;
-			}
-		}
-		igt_assert_f(ok, "Cannot capture all channels\n");
-	}
-
-	if (igt_frame_dump_is_enabled()) {
-		snprintf(dump_suffix, sizeof(dump_suffix),
-			 "capture-%s-%s-%dch-%dHz",
-			 name, snd_pcm_format_name(state->playback.format),
-			 state->playback.channels, state->playback.rate);
-
-		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
-							      state->capture.rate,
-							      state->capture.channels,
-							      &state->dump_path);
-		igt_assert_f(state->dump_fd >= 0,
-			     "Failed to create audio dump file\n");
-	}
-}
-
-static void audio_state_receive(struct audio_state *state,
-				int32_t **recv, size_t *recv_len)
-{
-	bool ok;
-	size_t page_count;
-	size_t recv_size;
-
-	ok = chamelium_stream_receive_realtime_audio(state->stream,
-						     &page_count,
-						     recv, recv_len);
-	igt_assert_f(ok, "Failed to receive audio from stream server\n");
-
-	state->msec = state->recv_pages * *recv_len
-		      / (double) state->capture.channels
-		      / (double) state->capture.rate * 1000;
-	state->recv_pages++;
-
-	if (state->dump_fd >= 0) {
-		recv_size = *recv_len * sizeof(int32_t);
-		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
-			     "Failed to write to audio dump file\n");
-	}
-}
-
-static void audio_state_stop(struct audio_state *state, bool success)
-{
-	bool ok;
-	int ret;
-	struct chamelium_audio_file *audio_file;
-	enum igt_log_level log_level;
-
-	igt_debug("Stopping audio playback\n");
-	state->run = false;
-	ret = pthread_join(state->thread, NULL);
-	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
-
-	ok = chamelium_stream_stop_realtime_audio(state->stream);
-	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
-
-	audio_file = chamelium_stop_capturing_audio(state->chamelium,
-						    state->port);
-	if (audio_file) {
-		igt_debug("Audio file saved on the Chamelium in %s\n",
-			  audio_file->path);
-		chamelium_destroy_audio_file(audio_file);
-	}
-
-	if (state->dump_fd >= 0) {
-		close(state->dump_fd);
-		state->dump_fd = -1;
-
-		if (success) {
-			/* Test succeeded, no need to keep the captured data */
-			unlink(state->dump_path);
-		} else
-			igt_debug("Saved captured audio data to %s\n",
-				  state->dump_path);
-		free(state->dump_path);
-		state->dump_path = NULL;
-	}
-
-	if (success)
-		log_level = IGT_LOG_DEBUG;
-	else
-		log_level = IGT_LOG_CRITICAL;
-
-	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
-		"sampling rate %d Hz and %d channels: %s\n",
-		state->name, snd_pcm_format_name(state->playback.format),
-		state->playback.rate, state->playback.channels,
-		success ? "ALL GREEN" : "FAILED");
-
-}
-
-static void check_audio_infoframe(struct audio_state *state)
-{
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_audio infoframe_audio;
-	struct infoframe_audio expected = {0};
-	bool ok;
-
-	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
-		igt_debug("Skipping audio InfoFrame check: "
-			  "Chamelium board doesn't support GetLastInfoFrame\n");
-		return;
-	}
-
-	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
-	expected.channel_count = state->playback.channels;
-	expected.sampling_freq = state->playback.rate;
-	expected.sample_size = snd_pcm_format_width(state->playback.format);
-
-	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
-						 CHAMELIUM_INFOFRAME_AUDIO);
-	if (infoframe == NULL && state->playback.channels <= 2) {
-		/* Audio InfoFrames are optional for mono and stereo audio */
-		igt_debug("Skipping audio InfoFrame check: "
-			  "no InfoFrame received\n");
-		return;
-	}
-	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
-
-	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
-				   infoframe->payload, infoframe->payload_size);
-	chamelium_infoframe_destroy(infoframe);
-	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
-
-	igt_debug("Checking audio InfoFrame:\n");
-	igt_debug("coding_type: got %d, expected %d\n",
-		  infoframe_audio.coding_type, expected.coding_type);
-	igt_debug("channel_count: got %d, expected %d\n",
-		  infoframe_audio.channel_count, expected.channel_count);
-	igt_debug("sampling_freq: got %d, expected %d\n",
-		  infoframe_audio.sampling_freq, expected.sampling_freq);
-	igt_debug("sample_size: got %d, expected %d\n",
-		  infoframe_audio.sample_size, expected.sample_size);
-
-	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
-		igt_assert(infoframe_audio.coding_type == expected.coding_type);
-	if (infoframe_audio.channel_count >= 0)
-		igt_assert(infoframe_audio.channel_count == expected.channel_count);
-	if (infoframe_audio.sampling_freq >= 0)
-		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
-	if (infoframe_audio.sample_size >= 0)
-		igt_assert(infoframe_audio.sample_size == expected.sample_size);
-}
-
-static int
-audio_output_frequencies_callback(void *data, void *buffer, int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	audio_signal_fill(state->signal, tmp, samples);
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool test_audio_frequencies(struct audio_state *state)
-{
-	int freq, step;
-	int32_t *recv, *buf;
-	double *channel;
-	size_t i, j, streak;
-	size_t recv_len, buf_len, buf_cap, channel_len;
-	bool success;
-	int capture_chan;
-
-	state->signal = audio_signal_init(state->playback.channels,
-					  state->playback.rate);
-	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
-
-	/* We'll choose different frequencies per channel to make sure they are
-	 * independent from each other. To do so, we'll add a different offset
-	 * to the base frequencies for each channel. We need to choose a big
-	 * enough offset so that we're sure to detect mixed up channels. We
-	 * choose an offset of two 2 bins in the final FFT to enforce a clear
-	 * difference.
-	 *
-	 * Note that we assume capture_rate == playback_rate. We'll assert this
-	 * later on. We cannot retrieve the capture rate before starting
-	 * playing audio, so we don't really have the choice.
-	 */
-	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
-	for (i = 0; i < test_frequencies_count; i++) {
-		for (j = 0; j < state->playback.channels; j++) {
-			freq = test_frequencies[i] + j * step;
-			audio_signal_add_frequency(state->signal, freq, j);
-		}
-	}
-	audio_signal_synthesize(state->signal);
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_frequencies_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	audio_state_start(state, "frequencies");
-
-	igt_assert_f(state->capture.rate == state->playback.rate,
-		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
-		     state->capture.rate, state->playback.rate);
-
-	/* Needs to be a multiple of 128, because that's the number of samples
-	 * we get per channel each time we receive an audio page from the
-	 * Chamelium device.
-	 *
-	 * Additionally, this value needs to be high enough to guarantee we
-	 * capture a full period of each sine we generate. If we capture 2048
-	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
-	 * sines. For lower sampling rates, the capture duration will be
-	 * longer.
-	 */
-	channel_len = CAPTURE_SAMPLES;
-	channel = malloc(sizeof(double) * channel_len);
-
-	buf_cap = state->capture.channels * channel_len;
-	buf = malloc(sizeof(int32_t) * buf_cap);
-	buf_len = 0;
-
-	recv = NULL;
-	recv_len = 0;
-
-	success = false;
-	streak = 0;
-	while (!success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
-		buf_len += recv_len;
-
-		if (buf_len < buf_cap)
-			continue;
-		igt_assert(buf_len == buf_cap);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (j = 0; j < state->playback.channels; j++) {
-			capture_chan = state->channel_mapping[j];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", j, capture_chan);
-
-			audio_extract_channel_s32_le(channel, channel_len,
-						     buf, buf_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			if (audio_signal_detect(state->signal,
-						state->capture.rate, j,
-						channel, channel_len))
-				streak++;
-			else
-				streak = 0;
-		}
-
-		buf_len = 0;
-
-		success = streak == MIN_STREAK * state->playback.channels;
-	}
-
-	audio_state_stop(state, success);
-
-	free(recv);
-	free(buf);
-	free(channel);
-	audio_signal_fini(state->signal);
-
-	check_audio_infoframe(state);
-
-	return success;
-}
-
-static int audio_output_flatline_callback(void *data, void *buffer,
-					     int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len, i;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	for (i = 0; i < len; i++)
-		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
-{
-	double expected, min, max;
-	size_t i;
-	bool ok;
-
-	min = max = NAN;
-	for (i = 0; i < buf_len; i++) {
-		if (isnan(min) || buf[i] < min)
-			min = buf[i];
-		if (isnan(max) || buf[i] > max)
-			max = buf[i];
-	}
-
-	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
-	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
-	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
-	if (ok)
-		igt_debug("Flatline wave amplitude detected\n");
-	else
-		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
-			  min, max);
-	return ok;
-}
-
-static ssize_t detect_falling_edge(double *buf, size_t buf_len)
-{
-	size_t i;
-
-	for (i = 0; i < buf_len; i++) {
-		if (buf[i] < 0)
-			return i;
-	}
-
-	return -1;
-}
-
-/** test_audio_flatline:
- *
- * Send a constant value (one positive, then a negative one) and check that:
- *
- * - The amplitude of the flatline is correct
- * - All channels switch from a positive signal to a negative one at the same
- *   time (ie. all channels are aligned)
- */
-static bool test_audio_flatline(struct audio_state *state)
-{
-	bool success, amp_success, align_success;
-	int32_t *recv;
-	size_t recv_len, i, channel_len;
-	ssize_t j;
-	int streak, capture_chan;
-	double *channel;
-	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_flatline_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	/* Start by sending a positive signal */
-	state->positive = true;
-
-	audio_state_start(state, "flatline");
-
-	for (i = 0; i < state->playback.channels; i++)
-		falling_edges[i] = -1;
-
-	recv = NULL;
-	recv_len = 0;
-	amp_success = false;
-	streak = 0;
-	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (i = 0; i < state->playback.channels; i++) {
-			capture_chan = state->channel_mapping[i];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", i, capture_chan);
-
-			channel_len = audio_extract_channel_s32_le(NULL, 0,
-								   recv, recv_len,
-								   state->capture.channels,
-								   capture_chan);
-			channel = malloc(channel_len * sizeof(double));
-			audio_extract_channel_s32_le(channel, channel_len,
-						     recv, recv_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			/* Check whether the amplitude is fine */
-			if (detect_flatline_amplitude(channel, channel_len,
-						      state->positive))
-				streak++;
-			else
-				streak = 0;
-
-			/* If we're now sending a negative signal, detect the
-			 * falling edge */
-			j = detect_falling_edge(channel, channel_len);
-			if (!state->positive && j >= 0) {
-				falling_edges[i] = recv_len * state->recv_pages
-						   + j;
-			}
-
-			free(channel);
-		}
-
-		amp_success = streak == MIN_STREAK * state->playback.channels;
-
-		if (amp_success && state->positive) {
-			/* Switch to a negative signal after we've detected the
-			 * positive one. */
-			state->positive = false;
-			amp_success = false;
-			streak = 0;
-			igt_debug("Switching to negative square wave\n");
-		}
-	}
-
-	/* Check alignment between all channels by comparing the index of the
-	 * falling edge. */
-	align_success = true;
-	for (i = 0; i < state->playback.channels; i++) {
-		if (falling_edges[i] < 0) {
-			igt_critical("Falling edge not detected for channel %zu\n",
-				     i);
-			align_success = false;
-			continue;
-		}
-
-		if (abs(falling_edges[0] - falling_edges[i]) >
-		    FLATLINE_ALIGN_ACCURACY) {
-			igt_critical("Channel alignment mismatch: "
-				     "channel 0 has a falling edge at index %d "
-				     "while channel %zu has index %d\n",
-				     falling_edges[0], i, falling_edges[i]);
-			align_success = false;
-		}
-	}
-
-	success = amp_success && align_success;
-	audio_state_stop(state, success);
-
-	free(recv);
-
-	return success;
-}
-
-static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
-				      int channels, int sampling_rate)
-{
-	if (!alsa_test_output_configuration(alsa, format, channels,
-					    sampling_rate)) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because at least one of the "
-			  "selected output devices doesn't support this "
-			  "configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	/* TODO: the Chamelium device sends a malformed signal for some audio
-	 * configurations. See crbug.com/950917 */
-	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
-			channels > 2) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because the Chamelium device "
-			  "doesn't support this configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	return true;
-}
-
-static const char test_display_audio_desc[] =
-	"Playback various audio signals with various audio formats/rates, "
-	"capture them and check they are correct";
-static void
-test_display_audio(data_t *data, struct chamelium_port *port,
-		   const char *audio_device, enum igt_custom_edid_type edid)
-{
-	bool run, success;
-	struct alsa *alsa;
-	int ret;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j;
-	int channels, sampling_rate;
-	snd_pcm_format_t format;
-	struct audio_state state;
-
-	igt_require(alsa_has_exclusive_access());
-
-	/* Old Chamelium devices need an update for DisplayPort audio and
-	 * chamelium_get_audio_format support. */
-	igt_require(chamelium_has_audio_support(data->chamelium, port));
-
-	alsa = alsa_init();
-	igt_assert(alsa);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because the receiver won't try to receive audio if
-	 * it doesn't receive video. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	run = false;
-	success = true;
-	for (i = 0; i < test_sampling_rates_count; i++) {
-		for (j = 0; j < test_formats_count; j++) {
-			ret = alsa_open_output(alsa, audio_device);
-			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
-
-			/* TODO: playback on all 8 available channels (this
-			 * isn't supported by Chamelium devices yet, see
-			 * https://crbug.com/950917) */
-			format = test_formats[j];
-			channels = PLAYBACK_CHANNELS;
-			sampling_rate = test_sampling_rates[i];
-
-			if (!check_audio_configuration(alsa, format, channels,
-						       sampling_rate))
-				continue;
-
-			run = true;
-
-			audio_state_init(&state, data, alsa, port,
-					 format, channels, sampling_rate);
-			success &= test_audio_frequencies(&state);
-			success &= test_audio_flatline(&state);
-			audio_state_fini(&state);
-
-			alsa_close_output(alsa);
-		}
-	}
-
-	/* Make sure we tested at least one frequency and format. */
-	igt_assert(run);
-	/* Make sure all runs were successful. */
-	igt_assert(success);
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-
-	free(alsa);
-}
-
-static const char test_display_audio_edid_desc[] =
-	"Plug a connector with an EDID suitable for audio, check ALSA's "
-	"EDID-Like Data reports the correct audio parameters";
-static void
-test_display_audio_edid(data_t *data, struct chamelium_port *port,
-			enum igt_custom_edid_type edid)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id;
-	struct eld_entry eld;
-	struct eld_sad *sad;
-
-	igt_require(eld_is_supported());
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because audio cannot be played on inactive
-	 * connectors. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	igt_assert(eld_get_igt(&eld));
-	igt_assert(eld.sads_len == 1);
-
-	sad = &eld.sads[0];
-	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
-	igt_assert(sad->channels == 2);
-	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
-		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
-	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
-		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-}
-
-static void randomize_plane_stride(data_t *data,
-				   uint32_t width, uint32_t height,
-				   uint32_t format, uint64_t modifier,
-				   size_t *stride)
-{
-	size_t stride_min;
-	uint32_t max_tile_w = 4, tile_w, tile_h;
-	int i;
-	struct igt_fb dummy;
-
-	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
-
-	/* Randomize the stride to less than twice the minimum. */
-	*stride = (rand() % stride_min) + stride_min;
-
-	/*
-	 * Create a dummy FB to determine bpp for each plane, and calculate
-	 * the maximum tile width from that.
-	 */
-	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
-	for (i = 0; i < dummy.num_planes; i++) {
-		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
-
-		if (tile_w > max_tile_w)
-			max_tile_w = tile_w;
-	}
-	igt_remove_fb(data->drm_fd, &dummy);
-
-	/*
-	 * Pixman requires the stride to be aligned to 32-bits, which is
-	 * reflected in the initial value of max_tile_w and the hw
-	 * may require a multiple of tile width, choose biggest of the 2.
-	 */
-	*stride = ALIGN(*stride, max_tile_w);
-}
-
-static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
-				  uint32_t height, uint32_t format,
-				  uint64_t *modifier)
-{
-	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
-		/* Randomize the column height to less than twice the minimum. */
-		size_t column_height = (rand() % height) + height;
-
-		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
-			  column_height);
-
-		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
-	}
-}
-
-static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
-				  drmModeModeInfo *mode,
-				  uint32_t *width, uint32_t *height,
-				  uint32_t *format, uint64_t *modifier,
-				  bool allow_yuv)
-{
-	int min_dim;
-	uint32_t idx[plane->format_mod_count];
-	unsigned int count = 0;
-	unsigned int i;
-
-	/* First pass to count the supported formats. */
-	for (i = 0; i < plane->format_mod_count; i++)
-		if (igt_fb_supported_format(plane->formats[i]) &&
-		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
-			idx[count++] = i;
-
-	igt_assert(count > 0);
-
-	i = idx[rand() % count];
-	*format = plane->formats[i];
-	*modifier = plane->modifiers[i];
-
-	update_tiled_modifier(plane, *width, *height, *format, modifier);
-
-	/*
-	 * Randomize width and height in the mode dimensions range.
-	 *
-	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
-	 * least min_dim, because src_w = width - (rand % w / 2).
-	 *
-	 * Use a minimum dimension of 16 for YUV, because planar YUV
-	 * subsamples the UV plane.
-	 */
-	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
-
-	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
-	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
-}
-
-static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
-			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
-			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
-			    struct igt_fb *fb)
-{
-	igt_plane_set_fb(plane, fb);
-
-	igt_plane_set_position(plane, crtc_x, crtc_y);
-	igt_plane_set_size(plane, crtc_w, crtc_h);
-
-	igt_fb_set_position(fb, plane, src_x, src_y);
-	igt_fb_set_size(fb, plane, src_w, src_h);
-}
-
-static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
-					drmModeModeInfo *mode,
-					struct igt_fb *fb,
-					uint32_t *src_w, uint32_t *src_h,
-					uint32_t *src_x, uint32_t *src_y,
-					uint32_t *crtc_w, uint32_t *crtc_h,
-					int32_t *crtc_x, int32_t *crtc_y,
-					bool allow_scaling)
-{
-	bool is_yuv = igt_format_is_yuv(fb->drm_format);
-	uint32_t width = fb->width, height = fb->height;
-	double ratio;
-	int ret;
-
-	/* Randomize source offset in the first half of the original size. */
-	*src_x = rand() % (width / 2);
-	*src_y = rand() % (height / 2);
-
-	/* The source size only includes the active source area. */
-	*src_w = width - *src_x;
-	*src_h = height - *src_y;
-
-	if (allow_scaling) {
-		*crtc_w = (rand() % mode->hdisplay) + 1;
-		*crtc_h = (rand() % mode->vdisplay) + 1;
-
-		/*
-		 * Don't bother with scaling if dimensions are quite close in
-		 * order to get non-scaling cases more frequently. Also limit
-		 * scaling to 3x to avoid agressive filtering that makes
-		 * comparison less reliable, and don't go above 2x downsampling
-		 * to avoid possible hw limitations.
-		 */
-
-		ratio = ((double) *crtc_w / *src_w);
-		if (ratio < 0.5)
-			*src_w = *crtc_w * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_w = *src_w;
-		else if (ratio > 3.0)
-			*crtc_w = *src_w * 3;
-
-		ratio = ((double) *crtc_h / *src_h);
-		if (ratio < 0.5)
-			*src_h = *crtc_h * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_h = *src_h;
-		else if (ratio > 3.0)
-			*crtc_h = *src_h * 3;
-	} else {
-		*crtc_w = *src_w;
-		*crtc_h = *src_h;
-	}
-
-	if (*crtc_w != *src_w || *crtc_h != *src_h) {
-		/*
-		 * When scaling is involved, make sure to not go off-bounds or
-		 * scaled clipping may result in decimal dimensions, that most
-		 * drivers don't support.
-		 */
-		if (*crtc_w < mode->hdisplay)
-			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
-		else
-			*crtc_x = 0;
-
-		if (*crtc_h < mode->vdisplay)
-			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
-		else
-			*crtc_y = 0;
-	} else {
-		/*
-		 * Randomize the on-crtc position and allow the plane to go
-		 * off-display by less than half of its on-crtc dimensions.
-		 */
-		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
-		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
-	}
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
-			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
-	ret = igt_display_try_commit_atomic(&data->display,
-					    DRM_MODE_ATOMIC_TEST_ONLY |
-					    DRM_MODE_ATOMIC_ALLOW_MODESET,
-					    NULL);
-	if (!ret)
-		return;
-
-	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
-	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
-
-	/* Make YUV coordinates a multiple of 2 and retry the math. */
-	if (is_yuv) {
-		*src_x &= ~1;
-		*src_y &= ~1;
-		*src_w &= ~1;
-		*src_h &= ~1;
-		/* To handle 1:1 scaling, clear crtc_w/h too. */
-		*crtc_w &= ~1;
-		*crtc_h &= ~1;
-
-		if (*crtc_x < 0 && (*crtc_x & 1))
-			(*crtc_x)++;
-		else
-			*crtc_x &= ~1;
-
-		/* If negative, round up to 0 instead of down */
-		if (*crtc_y < 0 && (*crtc_y & 1))
-			(*crtc_y)++;
-		else
-			*crtc_y &= ~1;
-
-		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-				*crtc_h, *crtc_x, *crtc_y, fb);
-		ret = igt_display_try_commit_atomic(&data->display,
-						DRM_MODE_ATOMIC_TEST_ONLY |
-						DRM_MODE_ATOMIC_ALLOW_MODESET,
-						NULL);
-		if (!ret)
-			return;
-	}
-
-	igt_assert(!ret || allow_scaling);
-	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
-		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
-
-	*crtc_w = *src_w;
-	*crtc_h = *src_h;
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-			*crtc_h, *crtc_x, *crtc_y, fb);
-	igt_display_commit_atomic(&data->display,
-				  DRM_MODE_ATOMIC_TEST_ONLY |
-				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-}
-
-static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
-			     uint32_t src_w, uint32_t src_h,
-			     uint32_t src_x, uint32_t src_y,
-			     uint32_t crtc_w, uint32_t crtc_h,
-			     int32_t crtc_x, int32_t crtc_y,
-			     struct igt_fb *fb)
-{
-	cairo_surface_t *surface;
-	cairo_surface_t *clipped_surface;
-	cairo_t *cr;
-
-	surface = igt_get_cairo_surface(data->drm_fd, fb);
-
-	if (src_x || src_y) {
-		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
-							     src_w, src_h);
-
-		cr = cairo_create(clipped_surface);
-
-		cairo_translate(cr, -1. * src_x, -1. * src_y);
-
-		cairo_set_source_surface(cr, surface, 0, 0);
-
-		cairo_paint(cr);
-		cairo_surface_flush(clipped_surface);
-
-		cairo_destroy(cr);
-	} else {
-		clipped_surface = surface;
-	}
-
-	cr = cairo_create(result);
-
-	cairo_translate(cr, crtc_x, crtc_y);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_scale(cr, (double) crtc_w / src_w,
-			    (double) crtc_h / src_h);
-	}
-
-	cairo_set_source_surface(cr, clipped_surface, 0, 0);
-	cairo_surface_destroy(clipped_surface);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_pattern_set_filter(cairo_get_source(cr),
-					 CAIRO_FILTER_BILINEAR);
-		cairo_pattern_set_extend(cairo_get_source(cr),
-					 CAIRO_EXTEND_NONE);
-	}
-
-	cairo_paint(cr);
-	cairo_surface_flush(result);
-
-	cairo_destroy(cr);
-}
-
-static void prepare_randomized_plane(data_t *data,
-				     drmModeModeInfo *mode,
-				     igt_plane_t *plane,
-				     struct igt_fb *overlay_fb,
-				     unsigned int index,
-				     cairo_surface_t *result_surface,
-				     bool allow_scaling, bool allow_yuv)
-{
-	struct igt_fb pattern_fb;
-	uint32_t overlay_fb_w, overlay_fb_h;
-	uint32_t overlay_src_w, overlay_src_h;
-	uint32_t overlay_src_x, overlay_src_y;
-	int32_t overlay_crtc_x, overlay_crtc_y;
-	uint32_t overlay_crtc_w, overlay_crtc_h;
-	uint32_t format;
-	uint64_t modifier;
-	size_t stride;
-	bool tiled;
-	int fb_id;
-
-	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
-			      &format, &modifier, allow_yuv);
-
-	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
-	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
-		  index, overlay_fb_w, overlay_fb_h,
-		  igt_format_str(format), tiled ? "tiled" : "linear");
-
-	/* Get a pattern framebuffer for the overlay plane. */
-	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
-					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
-			       format, modifier, &stride);
-
-	igt_debug("Plane %d: stride %ld\n", index, stride);
-
-	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
-					   modifier, stride);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_coordinates(data, plane, mode, overlay_fb,
-				    &overlay_src_w, &overlay_src_h,
-				    &overlay_src_x, &overlay_src_y,
-				    &overlay_crtc_w, &overlay_crtc_h,
-				    &overlay_crtc_x, &overlay_crtc_y,
-				    allow_scaling);
-
-	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
-		  overlay_src_w, overlay_src_h);
-	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
-		  overlay_src_x, overlay_src_y);
-	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
-		  overlay_crtc_w, overlay_crtc_h);
-	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
-		  overlay_crtc_x, overlay_crtc_y);
-
-	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
-			 overlay_src_x, overlay_src_y,
-			 overlay_crtc_w, overlay_crtc_h,
-			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
-
-	/* Remove the original pattern framebuffer. */
-	igt_remove_fb(data->drm_fd, &pattern_fb);
-}
-
-static const char test_display_planes_random_desc[] =
-	"Setup a few overlay planes with random parameters, capture the frame "
-	"and check it matches the expected output";
-static void test_display_planes_random(data_t *data,
-				       struct chamelium_port *port,
-				       enum chamelium_check check)
-{
-	igt_output_t *output;
-	drmModeModeInfo *mode;
-	igt_plane_t *primary_plane;
-	struct igt_fb primary_fb;
-	struct igt_fb result_fb;
-	struct igt_fb *overlay_fbs;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	unsigned int overlay_planes_max = 0;
-	unsigned int overlay_planes_count;
-	cairo_surface_t *result_surface;
-	int captured_frame_count;
-	bool allow_scaling;
-	bool allow_yuv;
-	unsigned int i;
-	unsigned int fb_id;
-
-	switch (check) {
-	case CHAMELIUM_CHECK_CRC:
-		allow_scaling = false;
-		allow_yuv = false;
-		break;
-	case CHAMELIUM_CHECK_CHECKERBOARD:
-		allow_scaling = true;
-		allow_yuv = true;
-		break;
-	default:
-		igt_assert(false);
-	}
-
-	srand(time(NULL));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Find the connector and pipe. */
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-
-	mode = igt_output_get_mode(output);
-
-	/* Get a framebuffer for the primary plane. */
-	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary_plane);
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
-	igt_assert(fb_id > 0);
-
-	/* Get a framebuffer for the cairo composition result. */
-	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
-			      mode->vdisplay, DRM_FORMAT_XRGB8888,
-			      DRM_FORMAT_MOD_LINEAR, &result_fb);
-	igt_assert(fb_id > 0);
-
-	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
-
-	/* Paint the primary framebuffer on the result surface. */
-	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
-			 &primary_fb);
-
-	/* Configure the primary plane. */
-	igt_plane_set_fb(primary_plane, &primary_fb);
-
-	overlay_planes_max =
-		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
-
-	/* Limit the number of planes to a reasonable scene. */
-	overlay_planes_max = min(overlay_planes_max, 4u);
-
-	overlay_planes_count = (rand() % overlay_planes_max) + 1;
-	igt_debug("Using %d overlay planes\n", overlay_planes_count);
-
-	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
-
-	for (i = 0; i < overlay_planes_count; i++) {
-		struct igt_fb *overlay_fb = &overlay_fbs[i];
-		igt_plane_t *plane =
-			igt_output_get_plane_type_index(output,
-							DRM_PLANE_TYPE_OVERLAY,
-							i);
-		igt_assert(plane);
-
-		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
-					 result_surface, allow_scaling,
-					 allow_yuv);
-	}
-
-	cairo_surface_destroy(result_surface);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&result_fb);
-
-	igt_display_commit2(&data->display, COMMIT_ATOMIC);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == 1);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium,
-						expected_crc, crc,
-						&result_fb, 0);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &result_fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	for (i = 0; i < overlay_planes_count; i++)
-		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
-
-	free(overlay_fbs);
-
-	igt_remove_fb(data->drm_fd, &primary_fb);
-	igt_remove_fb(data->drm_fd, &result_fb);
-}
-
-static const char test_hpd_without_ddc_desc[] =
-	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
-static void
-test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-	igt_flush_uevents(mon);
-
-	/* Disable the DDC on the connector and make sure we still get a
-	 * hotplug
-	 */
-	chamelium_port_set_ddc_state(data->chamelium, port, false);
-	chamelium_plug(data->chamelium, port);
-
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_assert_eq(chamelium_reprobe_connector(&data->display,
-						  data->chamelium, port),
-						  DRM_MODE_CONNECTED);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_hpd_storm_detect_desc[] =
-	"Trigger a series of hotplugs in a very small timeframe to simulate a"
-	"bad cable, check the kernel falls back to polling to avoid a hotplug "
-	"storm";
-static void
-test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
-{
-	struct udev_monitor *mon;
-	int count = 0;
-
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 1);
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-	igt_assert(igt_hpd_storm_detected(data->drm_fd));
-
-	mon = igt_watch_uevents();
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-
-	/*
-	 * Polling should have been enabled by the HPD storm at this point,
-	 * so we should only get at most 1 hotplug event
-	 */
-	igt_until_timeout(5)
-		count += igt_hotplug_detected(mon, 1);
-	igt_assert_lt(count, 2);
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_hpd_storm_disable_desc[] =
-	"Disable HPD storm detection, trigger a storm and check the kernel "
-	"doesn't detect one";
-static void
-test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
-{
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	chamelium_fire_hpd_pulses(data->chamelium, port,
-				  width, 10);
-	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
-
-	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,
-				   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;
-
-		monitor_edid *edid = &edids_list[i];
-		igt_info("Testing out the EDID for %s\n",
-			 monitor_edid_get_name(edid));
-
-		/* Getting and Setting the EDID on Chamelium. */
-		chamelium_edid =
-			get_chameleon_edid_from_monitor_edid(chamelium, 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);
-}
-
-static const char igt_edid_resolution_list_desc[] =
-	"Get an EDID with many modes of different configurations, set them on the screen and check the"
-	" screen resolution matches the mode resolution.";
-
-static void edid_resolution_list(data_t *data, struct chamelium_port *port)
-{
-	struct chamelium *chamelium = data->chamelium;
-	struct udev_monitor *mon = igt_watch_uevents();
-	drmModeConnector *connector;
-	drmModeModeInfoPtr modes;
-	int count_modes;
-	int i;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	chamelium_unplug(chamelium, port);
-	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
-
-	igt_flush_uevents(mon);
-	chamelium_plug(chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
-	igt_flush_uevents(mon);
-
-	connector = chamelium_port_get_connector(chamelium, port, true);
-	modes = connector->modes;
-	count_modes = connector->count_modes;
-
-	output = get_output_for_port(data, port);
-	pipe = get_pipe_for_output(&data->display, output);
-	igt_output_set_pipe(output, pipe);
-
-	for (i = 0; i < count_modes; ++i)
-		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
-
-	for (i = 0; i < count_modes; ++i) {
-		struct igt_fb fb = { 0 };
-		bool is_video_stable;
-		int screen_res_w, screen_res_h;
-
-		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
-			 modes[i].vrefresh);
-
-		/* Set the screen mode with the one we chose. */
-		create_fb_for_mode(data, &fb, &modes[i]);
-		enable_output(data, port, output, &modes[i], &fb);
-		is_video_stable = chamelium_port_wait_video_input_stable(
-			chamelium, port, 10);
-		igt_assert(is_video_stable);
-
-		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
-					      &screen_res_h);
-		igt_assert_eq(screen_res_w, modes[i].hdisplay);
-		igt_assert_eq(screen_res_h, modes[i].vdisplay);
-
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	drmModeFreeConnector(connector);
-}
-
-#define for_each_port(p, port)            \
-	for (p = 0, port = data.ports[p]; \
-	     p < data.port_count;         \
-	     p++, port = data.ports[p])
-
-#define connector_subtest(name__, type__)                    \
-	igt_subtest(name__)                                  \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-#define connector_dynamic_subtest(name__, type__)            \
-	igt_subtest_with_dynamic(name__)                     \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-
-static data_t data;
-
-IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
-igt_main
-{
-	struct chamelium_port *port;
-	int p;
-	size_t i;
-
-	igt_fixture {
-		/* So fbcon doesn't try to reprobe things itself */
-		kmstest_set_vt_graphics_mode();
-
-		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
-
-		/*
-		 * XXX: disabling modeset, can be removed when
-		 * igt_display_require will start doing this for us
-		 */
-		igt_display_commit2(&data.display, COMMIT_ATOMIC);
-
-		/* we need to initalize chamelium after igt_display_require */
-		data.chamelium = chamelium_init(data.drm_fd, &data.display);
-		igt_require(data.chamelium);
-
-		data.ports = chamelium_get_ports(data.chamelium,
-						 &data.port_count);
-
-		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
-			data.edids[i] = chamelium_new_edid(data.chamelium,
-							   igt_kms_get_custom_edid(i));
-		}
-	}
-
-	igt_describe("DisplayPort tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-fast", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("dp-edid-read", DisplayPort) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_4K,
-					       ARRAY_SIZE(DP_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-non-4k",
-				  DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
-					       ARRAY_SIZE(DP_EDIDS_NON_4K));
-
-		igt_describe(igt_edid_resolution_list_desc);
-		connector_subtest("dp-edid-resolution-list", DisplayPort)
-			edid_resolution_list(&data, port);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-suspend", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("dp-hpd-storm", DisplayPort)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("dp-hpd-storm-disable", DisplayPort)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("dp-crc-fast", DisplayPort)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("dp-frame-dump", DisplayPort)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("dp-mode-timings", DisplayPort)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("dp-audio", DisplayPort)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("dp-audio-edid", DisplayPort)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("HDMI tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-fast", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("hdmi-edid-read", HDMIA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("hdmi-hpd-storm", HDMIA)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("hdmi-crc-fast", HDMIA)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CRC, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-crc-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CRC);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (!igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-cmp-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CHECKERBOARD);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("hdmi-frame-dump", HDMIA)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("hdmi-mode-timings", HDMIA)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("hdmi-audio", HDMIA)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("hdmi-audio-edid", HDMIA)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_aspect_ratio_desc);
-		connector_subtest("hdmi-aspect-ratio", HDMIA)
-			test_display_aspect_ratio(&data, port);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("VGA tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-fast", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-enable-disable-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-with-enabled-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("vga-edid-read", VGA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-suspend", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-hibernate", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_without_ddc_desc);
-		connector_subtest("vga-hpd-without-ddc", VGA)
-			test_hpd_without_ddc(&data, port);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("vga-frame-dump", VGA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_ANALOG, 1);
-	}
-
-	igt_describe("Tests that operate on all connectors");
-	igt_subtest_group {
-
-		igt_fixture {
-			igt_require(data.port_count);
-		}
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-suspend")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_MEM,
-						       SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-hibernate")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_DISK,
-						       SUSPEND_TEST_DEVICES);
-	}
-
-	igt_describe(test_hotplug_for_each_pipe_desc);
-	connector_subtest("vga-hpd-for-each-pipe", VGA)
-		test_hotplug_for_each_pipe(&data, port);
-
-	igt_fixture {
-		igt_display_fini(&data.display);
-		close(data.drm_fd);
-	}
-}
diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
new file mode 100644
index 00000000..4d13744c
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_audio.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the Audio functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+/* Playback parameters control the audio signal we synthesize and send */
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_SAMPLES 1024
+
+/* Capture paremeters control the audio signal we receive */
+#define CAPTURE_SAMPLES 2048
+
+#define AUDIO_TIMEOUT 2000 /* ms */
+/* A streak of 3 gives confidence that the signal is good. */
+#define MIN_STREAK 3
+
+#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
+#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
+#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
+
+struct audio_state {
+	struct alsa *alsa;
+	struct chamelium *chamelium;
+	struct chamelium_port *port;
+	struct chamelium_stream *stream;
+
+	/* The capture format is only available after capture has started. */
+	struct {
+		snd_pcm_format_t format;
+		int channels;
+		int rate;
+	} playback, capture;
+
+	char *name;
+	struct audio_signal *signal; /* for frequencies test only */
+	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	size_t recv_pages;
+	int msec;
+
+	int dump_fd;
+	char *dump_path;
+
+	pthread_t thread;
+	atomic_bool run;
+	atomic_bool positive; /* for pulse test only */
+};
+
+/* TODO: enable >48KHz rates, these are not reliable */
+static int test_sampling_rates[] = {
+	32000, 44100, 48000,
+	/* 88200, */
+	/* 96000, */
+	/* 176400, */
+	/* 192000, */
+};
+
+static int test_sampling_rates_count =
+	sizeof(test_sampling_rates) / sizeof(int);
+
+/* Test frequencies (Hz): a sine signal will be generated for each.
+ *
+ * Depending on the sampling rate chosen, it might not be possible to properly
+ * detect the generated sine (see Nyquist–Shannon sampling theorem).
+ * Frequencies that can't be reliably detected will be automatically pruned in
+ * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
+ * tested with a 192KHz sampling rate.
+ */
+static int test_frequencies[] = {
+	300, 600, 1200, 10000, 80000,
+};
+
+static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
+
+static const snd_pcm_format_t test_formats[] = {
+	SND_PCM_FORMAT_S16_LE,
+	SND_PCM_FORMAT_S24_LE,
+	SND_PCM_FORMAT_S32_LE,
+};
+
+static const size_t test_formats_count =
+	sizeof(test_formats) / sizeof(test_formats[0]);
+
+static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
+			     struct alsa *alsa, struct chamelium_port *port,
+			     snd_pcm_format_t format, int channels, int rate)
+{
+	memset(state, 0, sizeof(*state));
+	state->dump_fd = -1;
+
+	state->alsa = alsa;
+	state->chamelium = data->chamelium;
+	state->port = port;
+
+	state->playback.format = format;
+	state->playback.channels = channels;
+	state->playback.rate = rate;
+
+	alsa_configure_output(alsa, format, channels, rate);
+
+	state->stream = chamelium_stream_init();
+	igt_assert_f(state->stream,
+		     "Failed to initialize Chamelium stream client\n");
+}
+
+static void audio_state_fini(struct audio_state *state)
+{
+	chamelium_stream_deinit(state->stream);
+	free(state->name);
+}
+
+static void *run_audio_thread(void *data)
+{
+	struct alsa *alsa = data;
+
+	alsa_run(alsa, -1);
+	return NULL;
+}
+
+static void audio_state_start(struct audio_state *state, const char *name)
+{
+	int ret;
+	bool ok;
+	size_t i, j;
+	enum chamelium_stream_realtime_mode stream_mode;
+	char dump_suffix[64];
+
+	free(state->name);
+	state->name = strdup(name);
+	state->recv_pages = 0;
+	state->msec = 0;
+
+	igt_debug("Starting %s test with playback format %s, "
+		  "sampling rate %d Hz and %d channels\n",
+		  name, snd_pcm_format_name(state->playback.format),
+		  state->playback.rate, state->playback.channels);
+
+	chamelium_start_capturing_audio(state->chamelium, state->port, false);
+
+	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
+	igt_assert_f(ok, "Failed to start streaming audio capture\n");
+
+	/* Start playing audio */
+	state->run = true;
+	ret = pthread_create(&state->thread, NULL, run_audio_thread,
+			     state->alsa);
+	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
+
+	/* The Chamelium device only supports this PCM format. */
+	state->capture.format = SND_PCM_FORMAT_S32_LE;
+
+	/* Only after we've started playing audio, we can retrieve the capture
+	 * format used by the Chamelium device. */
+	chamelium_get_audio_format(state->chamelium, state->port,
+				   &state->capture.rate,
+				   &state->capture.channels);
+	if (state->capture.rate == 0) {
+		igt_debug("Audio receiver doesn't indicate the capture "
+			  "sampling rate, assuming it's %d Hz\n",
+			  state->playback.rate);
+		state->capture.rate = state->playback.rate;
+	}
+
+	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
+					    state->channel_mapping);
+	/* Make sure we can capture all channels we send. */
+	for (i = 0; i < state->playback.channels; i++) {
+		ok = false;
+		for (j = 0; j < state->capture.channels; j++) {
+			if (state->channel_mapping[j] == i) {
+				ok = true;
+				break;
+			}
+		}
+		igt_assert_f(ok, "Cannot capture all channels\n");
+	}
+
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix),
+			 "capture-%s-%s-%dch-%dHz", name,
+			 snd_pcm_format_name(state->playback.format),
+			 state->playback.channels, state->playback.rate);
+
+		state->dump_fd = audio_create_wav_file_s32_le(
+			dump_suffix, state->capture.rate,
+			state->capture.channels, &state->dump_path);
+		igt_assert_f(state->dump_fd >= 0,
+			     "Failed to create audio dump file\n");
+	}
+}
+
+static void audio_state_receive(struct audio_state *state, int32_t **recv,
+				size_t *recv_len)
+{
+	bool ok;
+	size_t page_count;
+	size_t recv_size;
+
+	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
+						     recv, recv_len);
+	igt_assert_f(ok, "Failed to receive audio from stream server\n");
+
+	state->msec = state->recv_pages * *recv_len /
+		      (double)state->capture.channels /
+		      (double)state->capture.rate * 1000;
+	state->recv_pages++;
+
+	if (state->dump_fd >= 0) {
+		recv_size = *recv_len * sizeof(int32_t);
+		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
+				     recv_size,
+			     "Failed to write to audio dump file\n");
+	}
+}
+
+static void audio_state_stop(struct audio_state *state, bool success)
+{
+	bool ok;
+	int ret;
+	struct chamelium_audio_file *audio_file;
+	enum igt_log_level log_level;
+
+	igt_debug("Stopping audio playback\n");
+	state->run = false;
+	ret = pthread_join(state->thread, NULL);
+	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
+
+	ok = chamelium_stream_stop_realtime_audio(state->stream);
+	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
+
+	audio_file =
+		chamelium_stop_capturing_audio(state->chamelium, state->port);
+	if (audio_file) {
+		igt_debug("Audio file saved on the Chamelium in %s\n",
+			  audio_file->path);
+		chamelium_destroy_audio_file(audio_file);
+	}
+
+	if (state->dump_fd >= 0) {
+		close(state->dump_fd);
+		state->dump_fd = -1;
+
+		if (success) {
+			/* Test succeeded, no need to keep the captured data */
+			unlink(state->dump_path);
+		} else
+			igt_debug("Saved captured audio data to %s\n",
+				  state->dump_path);
+		free(state->dump_path);
+		state->dump_path = NULL;
+	}
+
+	if (success)
+		log_level = IGT_LOG_DEBUG;
+	else
+		log_level = IGT_LOG_CRITICAL;
+
+	igt_log(IGT_LOG_DOMAIN, log_level,
+		"Audio %s test result for format %s, "
+		"sampling rate %d Hz and %d channels: %s\n",
+		state->name, snd_pcm_format_name(state->playback.format),
+		state->playback.rate, state->playback.channels,
+		success ? "ALL GREEN" : "FAILED");
+}
+
+static void check_audio_infoframe(struct audio_state *state)
+{
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_audio infoframe_audio;
+	struct infoframe_audio expected = { 0 };
+	bool ok;
+
+	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
+		igt_debug("Skipping audio InfoFrame check: "
+			  "Chamelium board doesn't support GetLastInfoFrame\n");
+		return;
+	}
+
+	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
+	expected.channel_count = state->playback.channels;
+	expected.sampling_freq = state->playback.rate;
+	expected.sample_size = snd_pcm_format_width(state->playback.format);
+
+	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
+						 CHAMELIUM_INFOFRAME_AUDIO);
+	if (infoframe == NULL && state->playback.channels <= 2) {
+		/* Audio InfoFrames are optional for mono and stereo audio */
+		igt_debug("Skipping audio InfoFrame check: "
+			  "no InfoFrame received\n");
+		return;
+	}
+	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
+
+	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
+				   infoframe->payload, infoframe->payload_size);
+	chamelium_infoframe_destroy(infoframe);
+	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
+
+	igt_debug("Checking audio InfoFrame:\n");
+	igt_debug("coding_type: got %d, expected %d\n",
+		  infoframe_audio.coding_type, expected.coding_type);
+	igt_debug("channel_count: got %d, expected %d\n",
+		  infoframe_audio.channel_count, expected.channel_count);
+	igt_debug("sampling_freq: got %d, expected %d\n",
+		  infoframe_audio.sampling_freq, expected.sampling_freq);
+	igt_debug("sample_size: got %d, expected %d\n",
+		  infoframe_audio.sample_size, expected.sample_size);
+
+	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
+		igt_assert(infoframe_audio.coding_type == expected.coding_type);
+	if (infoframe_audio.channel_count >= 0)
+		igt_assert(infoframe_audio.channel_count ==
+			   expected.channel_count);
+	if (infoframe_audio.sampling_freq >= 0)
+		igt_assert(infoframe_audio.sampling_freq ==
+			   expected.sampling_freq);
+	if (infoframe_audio.sample_size >= 0)
+		igt_assert(infoframe_audio.sample_size == expected.sample_size);
+}
+
+static int audio_output_frequencies_callback(void *data, void *buffer,
+					     int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	audio_signal_fill(state->signal, tmp, samples);
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool test_audio_frequencies(struct audio_state *state)
+{
+	int freq, step;
+	int32_t *recv, *buf;
+	double *channel;
+	size_t i, j, streak;
+	size_t recv_len, buf_len, buf_cap, channel_len;
+	bool success;
+	int capture_chan;
+
+	state->signal = audio_signal_init(state->playback.channels,
+					  state->playback.rate);
+	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
+
+	/* We'll choose different frequencies per channel to make sure they are
+	 * independent from each other. To do so, we'll add a different offset
+	 * to the base frequencies for each channel. We need to choose a big
+	 * enough offset so that we're sure to detect mixed up channels. We
+	 * choose an offset of two 2 bins in the final FFT to enforce a clear
+	 * difference.
+	 *
+	 * Note that we assume capture_rate == playback_rate. We'll assert this
+	 * later on. We cannot retrieve the capture rate before starting
+	 * playing audio, so we don't really have the choice.
+	 */
+	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
+	for (i = 0; i < test_frequencies_count; i++) {
+		for (j = 0; j < state->playback.channels; j++) {
+			freq = test_frequencies[i] + j * step;
+			audio_signal_add_frequency(state->signal, freq, j);
+		}
+	}
+	audio_signal_synthesize(state->signal);
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_frequencies_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	audio_state_start(state, "frequencies");
+
+	igt_assert_f(state->capture.rate == state->playback.rate,
+		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
+		     state->capture.rate, state->playback.rate);
+
+	/* Needs to be a multiple of 128, because that's the number of samples
+	 * we get per channel each time we receive an audio page from the
+	 * Chamelium device.
+	 *
+	 * Additionally, this value needs to be high enough to guarantee we
+	 * capture a full period of each sine we generate. If we capture 2048
+	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
+	 * sines. For lower sampling rates, the capture duration will be
+	 * longer.
+	 */
+	channel_len = CAPTURE_SAMPLES;
+	channel = malloc(sizeof(double) * channel_len);
+
+	buf_cap = state->capture.channels * channel_len;
+	buf = malloc(sizeof(int32_t) * buf_cap);
+	buf_len = 0;
+
+	recv = NULL;
+	recv_len = 0;
+
+	success = false;
+	streak = 0;
+	while (!success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
+		buf_len += recv_len;
+
+		if (buf_len < buf_cap)
+			continue;
+		igt_assert(buf_len == buf_cap);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (j = 0; j < state->playback.channels; j++) {
+			capture_chan = state->channel_mapping[j];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  j, capture_chan);
+
+			audio_extract_channel_s32_le(channel, channel_len, buf,
+						     buf_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			if (audio_signal_detect(state->signal,
+						state->capture.rate, j, channel,
+						channel_len))
+				streak++;
+			else
+				streak = 0;
+		}
+
+		buf_len = 0;
+
+		success = streak == MIN_STREAK * state->playback.channels;
+	}
+
+	audio_state_stop(state, success);
+
+	free(recv);
+	free(buf);
+	free(channel);
+	audio_signal_fini(state->signal);
+
+	check_audio_infoframe(state);
+
+	return success;
+}
+
+static int audio_output_flatline_callback(void *data, void *buffer, int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len, i;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	for (i = 0; i < len; i++)
+		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
+{
+	double expected, min, max;
+	size_t i;
+	bool ok;
+
+	min = max = NAN;
+	for (i = 0; i < buf_len; i++) {
+		if (isnan(min) || buf[i] < min)
+			min = buf[i];
+		if (isnan(max) || buf[i] > max)
+			max = buf[i];
+	}
+
+	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
+	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
+	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
+	if (ok)
+		igt_debug("Flatline wave amplitude detected\n");
+	else
+		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
+			  min, max);
+	return ok;
+}
+
+static ssize_t detect_falling_edge(double *buf, size_t buf_len)
+{
+	size_t i;
+
+	for (i = 0; i < buf_len; i++) {
+		if (buf[i] < 0)
+			return i;
+	}
+
+	return -1;
+}
+
+/** test_audio_flatline:
+ *
+ * Send a constant value (one positive, then a negative one) and check that:
+ *
+ * - The amplitude of the flatline is correct
+ * - All channels switch from a positive signal to a negative one at the same
+ *   time (ie. all channels are aligned)
+ */
+static bool test_audio_flatline(struct audio_state *state)
+{
+	bool success, amp_success, align_success;
+	int32_t *recv;
+	size_t recv_len, i, channel_len;
+	ssize_t j;
+	int streak, capture_chan;
+	double *channel;
+	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_flatline_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	/* Start by sending a positive signal */
+	state->positive = true;
+
+	audio_state_start(state, "flatline");
+
+	for (i = 0; i < state->playback.channels; i++)
+		falling_edges[i] = -1;
+
+	recv = NULL;
+	recv_len = 0;
+	amp_success = false;
+	streak = 0;
+	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (i = 0; i < state->playback.channels; i++) {
+			capture_chan = state->channel_mapping[i];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  i, capture_chan);
+
+			channel_len = audio_extract_channel_s32_le(
+				NULL, 0, recv, recv_len,
+				state->capture.channels, capture_chan);
+			channel = malloc(channel_len * sizeof(double));
+			audio_extract_channel_s32_le(channel, channel_len, recv,
+						     recv_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			/* Check whether the amplitude is fine */
+			if (detect_flatline_amplitude(channel, channel_len,
+						      state->positive))
+				streak++;
+			else
+				streak = 0;
+
+			/* If we're now sending a negative signal, detect the
+			 * falling edge */
+			j = detect_falling_edge(channel, channel_len);
+			if (!state->positive && j >= 0) {
+				falling_edges[i] =
+					recv_len * state->recv_pages + j;
+			}
+
+			free(channel);
+		}
+
+		amp_success = streak == MIN_STREAK * state->playback.channels;
+
+		if (amp_success && state->positive) {
+			/* Switch to a negative signal after we've detected the
+			 * positive one. */
+			state->positive = false;
+			amp_success = false;
+			streak = 0;
+			igt_debug("Switching to negative square wave\n");
+		}
+	}
+
+	/* Check alignment between all channels by comparing the index of the
+	 * falling edge. */
+	align_success = true;
+	for (i = 0; i < state->playback.channels; i++) {
+		if (falling_edges[i] < 0) {
+			igt_critical(
+				"Falling edge not detected for channel %zu\n",
+				i);
+			align_success = false;
+			continue;
+		}
+
+		if (abs(falling_edges[0] - falling_edges[i]) >
+		    FLATLINE_ALIGN_ACCURACY) {
+			igt_critical("Channel alignment mismatch: "
+				     "channel 0 has a falling edge at index %d "
+				     "while channel %zu has index %d\n",
+				     falling_edges[0], i, falling_edges[i]);
+			align_success = false;
+		}
+	}
+
+	success = amp_success && align_success;
+	audio_state_stop(state, success);
+
+	free(recv);
+
+	return success;
+}
+
+static bool check_audio_configuration(struct alsa *alsa,
+				      snd_pcm_format_t format, int channels,
+				      int sampling_rate)
+{
+	if (!alsa_test_output_configuration(alsa, format, channels,
+					    sampling_rate)) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because at least one of the "
+			  "selected output devices doesn't support this "
+			  "configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	/* TODO: the Chamelium device sends a malformed signal for some audio
+	 * configurations. See crbug.com/950917 */
+	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
+	    channels > 2) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because the Chamelium device "
+			  "doesn't support this configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	return true;
+}
+
+static const char test_display_audio_desc[] =
+	"Playback various audio signals with various audio formats/rates, "
+	"capture them and check they are correct";
+static void test_display_audio(chamelium_data_t *data,
+			       struct chamelium_port *port,
+			       const char *audio_device,
+			       enum igt_custom_edid_type edid)
+{
+	bool run, success;
+	struct alsa *alsa;
+	int ret;
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id, i, j;
+	int channels, sampling_rate;
+	snd_pcm_format_t format;
+	struct audio_state state;
+
+	igt_require(alsa_has_exclusive_access());
+
+	/* Old Chamelium devices need an update for DisplayPort audio and
+	 * chamelium_get_audio_format support. */
+	igt_require(chamelium_has_audio_support(data->chamelium, port));
+
+	alsa = alsa_init();
+	igt_assert(alsa);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because the receiver won't try to receive audio if
+	 * it doesn't receive video. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	run = false;
+	success = true;
+	for (i = 0; i < test_sampling_rates_count; i++) {
+		for (j = 0; j < test_formats_count; j++) {
+			ret = alsa_open_output(alsa, audio_device);
+			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
+
+			/* TODO: playback on all 8 available channels (this
+			 * isn't supported by Chamelium devices yet, see
+			 * https://crbug.com/950917) */
+			format = test_formats[j];
+			channels = PLAYBACK_CHANNELS;
+			sampling_rate = test_sampling_rates[i];
+
+			if (!check_audio_configuration(alsa, format, channels,
+						       sampling_rate))
+				continue;
+
+			run = true;
+
+			audio_state_init(&state, data, alsa, port, format,
+					 channels, sampling_rate);
+			success &= test_audio_frequencies(&state);
+			success &= test_audio_flatline(&state);
+			audio_state_fini(&state);
+
+			alsa_close_output(alsa);
+		}
+	}
+
+	/* Make sure we tested at least one frequency and format. */
+	igt_assert(run);
+	/* Make sure all runs were successful. */
+	igt_assert(success);
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+
+	free(alsa);
+}
+
+static const char test_display_audio_edid_desc[] =
+	"Plug a connector with an EDID suitable for audio, check ALSA's "
+	"EDID-Like Data reports the correct audio parameters";
+static void test_display_audio_edid(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_custom_edid_type edid)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id;
+	struct eld_entry eld;
+	struct eld_sad *sad;
+
+	igt_require(eld_is_supported());
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because audio cannot be played on inactive
+	 * connectors. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	igt_assert(eld_get_igt(&eld));
+	igt_assert(eld.sads_len == 1);
+
+	sad = &eld.sads[0];
+	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
+	igt_assert(sad->channels == 2);
+	igt_assert(sad->rates ==
+		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
+		    CEA_SAD_SAMPLING_RATE_48KHZ));
+	igt_assert(sad->bits ==
+		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
+		    CEA_SAD_SAMPLE_SIZE_24));
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+}
+
+IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("dp-audio", DisplayPort) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("dp-audio-edid", DisplayPort)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_DP_AUDIO);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("hdmi-audio-edid", HDMIA)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_HDMI_AUDIO);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
similarity index 100%
rename from tests/chamelium/kms_color_chamelium.c
rename to tests/chamelium/kms_chamelium_color.c
diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
new file mode 100644
index 00000000..0b28189e
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_edid.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the EDID functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include <xf86drmMode.h>
+
+#include "igt_chamelium.h"
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+#include "monitor_edids/dp_edids.h"
+#include "monitor_edids/hdmi_edids.h"
+#include "monitor_edids/monitor_edids_helper.h"
+
+#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
+
+static void get_connectors_link_status_failed(chamelium_data_t *data,
+					      bool *link_status_failed)
+{
+	drmModeConnector *connector;
+	uint64_t link_status;
+	drmModePropertyPtr prop;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		connector = chamelium_port_get_connector(data->chamelium,
+							 data->ports[p], false);
+
+		igt_assert(kmstest_get_property(
+			data->drm_fd, connector->connector_id,
+			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
+			&link_status, &prop));
+
+		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
+
+		drmModeFreeProperty(prop);
+		drmModeFreeConnector(connector);
+	}
+}
+
+static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
+		       drmModeModeInfo *mode)
+{
+	struct chamelium_video_params video_params = { 0 };
+	double mode_clock;
+	int mode_hsync_offset, mode_vsync_offset;
+	int mode_hsync_width, mode_vsync_width;
+	int mode_hsync_polarity, mode_vsync_polarity;
+
+	chamelium_port_get_video_params(chamelium, port, &video_params);
+
+	mode_clock = (double)mode->clock / 1000;
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
+		/* this is what chamelium understands as offsets for DP */
+		mode_hsync_offset = mode->htotal - mode->hsync_start;
+		mode_vsync_offset = mode->vtotal - mode->vsync_start;
+	} else {
+		/* and this is what they are for other connectors */
+		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
+		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
+	}
+
+	mode_hsync_width = mode->hsync_end - mode->hsync_start;
+	mode_vsync_width = mode->vsync_end - mode->vsync_start;
+
+	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	igt_debug("Checking video mode:\n");
+	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
+		  mode_clock, MODE_CLOCK_ACCURACY * 100);
+	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
+		  mode->hdisplay);
+	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
+		  mode->vdisplay);
+	igt_debug("hsync_offset: got %d, expected %d\n",
+		  video_params.hsync_offset, mode_hsync_offset);
+	igt_debug("vsync_offset: got %d, expected %d\n",
+		  video_params.vsync_offset, mode_vsync_offset);
+	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
+		  mode->htotal);
+	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
+		  mode->vtotal);
+	igt_debug("hsync_width: got %d, expected %d\n",
+		  video_params.hsync_width, mode_hsync_width);
+	igt_debug("vsync_width: got %d, expected %d\n",
+		  video_params.vsync_width, mode_vsync_width);
+	igt_debug("hsync_polarity: got %d, expected %d\n",
+		  video_params.hsync_polarity, mode_hsync_polarity);
+	igt_debug("vsync_polarity: got %d, expected %d\n",
+		  video_params.vsync_polarity, mode_vsync_polarity);
+
+	if (!isnan(video_params.clock)) {
+		igt_assert(video_params.clock >
+			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
+		igt_assert(video_params.clock <
+			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
+	}
+	igt_assert(video_params.hactive == mode->hdisplay);
+	igt_assert(video_params.vactive == mode->vdisplay);
+	igt_assert(video_params.hsync_offset == mode_hsync_offset);
+	igt_assert(video_params.vsync_offset == mode_vsync_offset);
+	igt_assert(video_params.htotal == mode->htotal);
+	igt_assert(video_params.vtotal == mode->vtotal);
+	igt_assert(video_params.hsync_width == mode_hsync_width);
+	igt_assert(video_params.vsync_width == mode_vsync_width);
+	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
+	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
+}
+
+static const char igt_custom_edid_type_read_desc[] =
+	"Make sure the EDID exposed by KMS is the same as the screen's";
+static void igt_custom_edid_type_read(chamelium_data_t *data,
+				      struct chamelium_port *port,
+				      enum igt_custom_edid_type edid)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector;
+	size_t raw_edid_size;
+	const struct edid *raw_edid;
+	uint64_t edid_blob_id;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_skip_on(chamelium_check_analog_bridge(data, port));
+
+	connector = chamelium_port_get_connector(data->chamelium, port, true);
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob_id != 0);
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
+	raw_edid_size = edid_get_size(raw_edid);
+	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+}
+
+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(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   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;
+
+		monitor_edid *edid = &edids_list[i];
+		igt_info("Testing out the EDID for %s\n",
+			 monitor_edid_get_name(edid));
+
+		/* Getting and Setting the EDID on Chamelium. */
+		chamelium_edid =
+			get_chameleon_edid_from_monitor_edid(chamelium, 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);
+		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
+		chamelium_create_fb_for_mode(data, &fb, &mode);
+		output = chamelium_get_output_for_port(data, port);
+		pipe = chamelium_get_pipe_for_output(&data->display, output);
+		igt_output_set_pipe(output, pipe);
+		chamelium_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);
+}
+
+static const char igt_edid_resolution_list_desc[] =
+	"Get an EDID with many modes of different configurations, set them on the screen and check the"
+	" screen resolution matches the mode resolution.";
+
+static void edid_resolution_list(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct chamelium *chamelium = data->chamelium;
+	struct udev_monitor *mon = igt_watch_uevents();
+	drmModeConnector *connector;
+	drmModeModeInfoPtr modes;
+	int count_modes;
+	int i;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	chamelium_unplug(chamelium, port);
+	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
+
+	igt_flush_uevents(mon);
+	chamelium_plug(chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_CONNECTED);
+	igt_flush_uevents(mon);
+
+	connector = chamelium_port_get_connector(chamelium, port, true);
+	modes = connector->modes;
+	count_modes = connector->count_modes;
+
+	output = chamelium_get_output_for_port(data, port);
+	pipe = chamelium_get_pipe_for_output(&data->display, output);
+	igt_output_set_pipe(output, pipe);
+
+	for (i = 0; i < count_modes; ++i)
+		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
+
+	for (i = 0; i < count_modes; ++i) {
+		struct igt_fb fb = { 0 };
+		bool is_video_stable;
+		int screen_res_w, screen_res_h;
+
+		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
+			 modes[i].vrefresh);
+
+		/* Set the screen mode with the one we chose. */
+		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
+		chamelium_enable_output(data, port, output, &modes[i], &fb);
+		is_video_stable = chamelium_port_wait_video_input_stable(
+			chamelium, port, 10);
+		igt_assert(is_video_stable);
+
+		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
+					      &screen_res_h);
+		igt_assert_eq(screen_res_w, modes[i].hdisplay);
+		igt_assert_eq(screen_res_h, modes[i].vdisplay);
+
+		igt_remove_fb(data->drm_fd, &fb);
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_suspend_resume_edid_change_desc[] =
+	"Simulate a screen being unplugged and another screen being plugged "
+	"during suspend, check that a uevent is sent and connector status is "
+	"updated";
+static void test_suspend_resume_edid_change(chamelium_data_t *data,
+					    struct chamelium_port *port,
+					    enum igt_suspend_state state,
+					    enum igt_suspend_test test,
+					    enum igt_custom_edid_type edid,
+					    enum igt_custom_edid_type alt_edid)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	bool link_status_failed[2][data->port_count];
+	int p;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Catch the event and flush all remaining ones. */
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_flush_uevents(mon);
+
+	/* First plug in the port */
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	/*
+	 * Change the edid before we suspend. On resume, the machine should
+	 * notice the EDID change and fire a hotplug event.
+	 */
+	chamelium_set_edid(data, port, alt_edid);
+
+	get_connectors_link_status_failed(data, link_status_failed[0]);
+
+	igt_flush_uevents(mon);
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	get_connectors_link_status_failed(data, link_status_failed[1]);
+
+	for (p = 0; p < data->port_count; p++)
+		igt_skip_on(!link_status_failed[0][p] &&
+			    link_status_failed[1][p]);
+}
+
+static const char test_mode_timings_desc[] =
+	"For each mode of the IGT base EDID, perform a modeset and check the "
+	"mode detected by the Chamelium receiver matches the mode we set";
+static void test_mode_timings(chamelium_data_t *data,
+			      struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	igt_require(chamelium_supports_get_video_params(data->chamelium));
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+		int fb_id;
+		struct igt_fb fb;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		/* Trigger the FSM */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
+
+		check_mode(data->chamelium, port, mode);
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("dp-edid-read", DisplayPort)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_4K,
+					       ARRAY_SIZE(DP_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-non-4k",
+				  DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
+					       ARRAY_SIZE(DP_EDIDS_NON_4K));
+
+		igt_describe(igt_edid_resolution_list_desc);
+		connector_subtest("dp-edid-resolution-list", DisplayPort)
+			edid_resolution_list(&data, port);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-hibernate",
+				  DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("dp-mode-timings", DisplayPort)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("hdmi-edid-read", HDMIA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("hdmi-mode-timings", HDMIA)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("vga-edid-read", VGA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
new file mode 100644
index 00000000..008bc34b
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_frames.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Lyude Paul <lyude@redhat.com>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+#define connector_dynamic_subtest(name__, type__)                   \
+	igt_subtest_with_dynamic(name__)                            \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+struct vic_mode {
+	int hactive, vactive;
+	int vrefresh; /* Hz */
+	uint32_t picture_ar;
+};
+
+static int chamelium_vga_modes[][2] = {
+	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
+	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
+	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
+	{ 640, 480 },	{ -1, -1 },
+};
+
+/* Maps Video Identification Codes to a mode */
+static const struct vic_mode vic_modes[] = {
+	[16] = {
+		.hactive = 1920,
+		.vactive = 1080,
+		.vrefresh = 60,
+		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
+	},
+};
+
+/* Maps aspect ratios to their mode flag */
+static const uint32_t mode_ar_flags[] = {
+	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
+};
+
+static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
+{
+	int i = 0;
+
+	while (chamelium_vga_modes[i][0] != -1) {
+		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
+		    mode->vdisplay == chamelium_vga_modes[i][1])
+			return false;
+
+		i++;
+	}
+
+	return true;
+}
+
+static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
+			    igt_output_t *output, drmModeModeInfo *mode,
+			    uint32_t fourcc, enum chamelium_check check,
+			    int count)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+	struct igt_fb frame_fb, fb;
+	int i, fb_id, captured_frame_count;
+	int frame_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &fb);
+	igt_assert(fb_id > 0);
+
+	frame_id =
+		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
+	igt_assert(frame_id > 0);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
+
+	chamelium_enable_output(data, port, output, mode, &frame_fb);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		igt_crc_t *expected_crc;
+		igt_crc_t *crc;
+
+		/* We want to keep the display running for a little bit, since
+		 * there's always the potential the driver isn't able to keep
+		 * the display running properly for very long
+		 */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == count);
+
+		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		for (i = 0; i < captured_frame_count; i++)
+			chamelium_assert_crc_eq_or_dump(
+				data->chamelium, expected_crc, &crc[i], &fb, i);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_ANALOG ||
+		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		igt_assert(count == 1);
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+
+		if (check == CHAMELIUM_CHECK_ANALOG)
+			chamelium_crop_analog_frame(dump, mode->hdisplay,
+						    mode->vdisplay);
+
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	igt_remove_fb(data->drm_fd, &frame_fb);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static enum infoframe_avi_picture_aspect_ratio
+get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
+{
+	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
+	switch (aspect_ratio) {
+	case DRM_MODE_PICTURE_ASPECT_4_3:
+		return INFOFRAME_AVI_PIC_AR_4_3;
+	case DRM_MODE_PICTURE_ASPECT_16_9:
+		return INFOFRAME_AVI_PIC_AR_16_9;
+	default:
+		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
+	}
+}
+
+static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
+				 drmModeModeInfo *drm_mode)
+{
+	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
+
+	return vic_mode->hactive == drm_mode->hdisplay &&
+	       vic_mode->vactive == drm_mode->vdisplay &&
+	       vic_mode->vrefresh == drm_mode->vrefresh &&
+	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
+}
+
+static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
+				   uint32_t height, uint32_t format,
+				   uint64_t modifier, size_t *stride)
+{
+	size_t stride_min;
+	uint32_t max_tile_w = 4, tile_w, tile_h;
+	int i;
+	struct igt_fb dummy;
+
+	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
+
+	/* Randomize the stride to less than twice the minimum. */
+	*stride = (rand() % stride_min) + stride_min;
+
+	/*
+	 * Create a dummy FB to determine bpp for each plane, and calculate
+	 * the maximum tile width from that.
+	 */
+	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
+	for (i = 0; i < dummy.num_planes; i++) {
+		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
+				     &tile_w, &tile_h);
+
+		if (tile_w > max_tile_w)
+			max_tile_w = tile_w;
+	}
+	igt_remove_fb(data->drm_fd, &dummy);
+
+	/*
+	 * Pixman requires the stride to be aligned to 32-bits, which is
+	 * reflected in the initial value of max_tile_w and the hw
+	 * may require a multiple of tile width, choose biggest of the 2.
+	 */
+	*stride = ALIGN(*stride, max_tile_w);
+}
+
+static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
+				  uint32_t height, uint32_t format,
+				  uint64_t *modifier)
+{
+	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
+		/* Randomize the column height to less than twice the minimum.
+		 */
+		size_t column_height = (rand() % height) + height;
+
+		igt_debug(
+			"Selecting VC4 SAND256 tiling with column height %ld\n",
+			column_height);
+
+		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
+			column_height);
+	}
+}
+
+static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
+				  drmModeModeInfo *mode, uint32_t *width,
+				  uint32_t *height, uint32_t *format,
+				  uint64_t *modifier, bool allow_yuv)
+{
+	int min_dim;
+	uint32_t idx[plane->format_mod_count];
+	unsigned int count = 0;
+	unsigned int i;
+
+	/* First pass to count the supported formats. */
+	for (i = 0; i < plane->format_mod_count; i++)
+		if (igt_fb_supported_format(plane->formats[i]) &&
+		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
+			idx[count++] = i;
+
+	igt_assert(count > 0);
+
+	i = idx[rand() % count];
+	*format = plane->formats[i];
+	*modifier = plane->modifiers[i];
+
+	update_tiled_modifier(plane, *width, *height, *format, modifier);
+
+	/*
+	 * Randomize width and height in the mode dimensions range.
+	 *
+	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
+	 * least min_dim, because src_w = width - (rand % w / 2).
+	 *
+	 * Use a minimum dimension of 16 for YUV, because planar YUV
+	 * subsamples the UV plane.
+	 */
+	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
+
+	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
+	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
+}
+
+static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
+			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
+			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
+			    struct igt_fb *fb)
+{
+	igt_plane_set_fb(plane, fb);
+
+	igt_plane_set_position(plane, crtc_x, crtc_y);
+	igt_plane_set_size(plane, crtc_w, crtc_h);
+
+	igt_fb_set_position(fb, plane, src_x, src_y);
+	igt_fb_set_size(fb, plane, src_w, src_h);
+}
+
+static void randomize_plane_coordinates(
+	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
+	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
+	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
+	int32_t *crtc_y, bool allow_scaling)
+{
+	bool is_yuv = igt_format_is_yuv(fb->drm_format);
+	uint32_t width = fb->width, height = fb->height;
+	double ratio;
+	int ret;
+
+	/* Randomize source offset in the first half of the original size. */
+	*src_x = rand() % (width / 2);
+	*src_y = rand() % (height / 2);
+
+	/* The source size only includes the active source area. */
+	*src_w = width - *src_x;
+	*src_h = height - *src_y;
+
+	if (allow_scaling) {
+		*crtc_w = (rand() % mode->hdisplay) + 1;
+		*crtc_h = (rand() % mode->vdisplay) + 1;
+
+		/*
+		 * Don't bother with scaling if dimensions are quite close in
+		 * order to get non-scaling cases more frequently. Also limit
+		 * scaling to 3x to avoid aggressive filtering that makes
+		 * comparison less reliable, and don't go above 2x downsampling
+		 * to avoid possible hw limitations.
+		 */
+
+		ratio = ((double)*crtc_w / *src_w);
+		if (ratio < 0.5)
+			*src_w = *crtc_w * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_w = *src_w;
+		else if (ratio > 3.0)
+			*crtc_w = *src_w * 3;
+
+		ratio = ((double)*crtc_h / *src_h);
+		if (ratio < 0.5)
+			*src_h = *crtc_h * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_h = *src_h;
+		else if (ratio > 3.0)
+			*crtc_h = *src_h * 3;
+	} else {
+		*crtc_w = *src_w;
+		*crtc_h = *src_h;
+	}
+
+	if (*crtc_w != *src_w || *crtc_h != *src_h) {
+		/*
+		 * When scaling is involved, make sure to not go off-bounds or
+		 * scaled clipping may result in decimal dimensions, that most
+		 * drivers don't support.
+		 */
+		if (*crtc_w < mode->hdisplay)
+			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
+		else
+			*crtc_x = 0;
+
+		if (*crtc_h < mode->vdisplay)
+			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
+		else
+			*crtc_y = 0;
+	} else {
+		/*
+		 * Randomize the on-crtc position and allow the plane to go
+		 * off-display by less than half of its on-crtc dimensions.
+		 */
+		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
+		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
+	}
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	ret = igt_display_try_commit_atomic(
+		&data->display,
+		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
+		NULL);
+	if (!ret)
+		return;
+
+	/* Coordinates are logged in the dumped debug log, so only report w/h on
+	 * failure here. */
+	igt_assert_f(ret != -ENOSPC,
+		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
+		     width, height);
+
+	/* Make YUV coordinates a multiple of 2 and retry the math. */
+	if (is_yuv) {
+		*src_x &= ~1;
+		*src_y &= ~1;
+		*src_w &= ~1;
+		*src_h &= ~1;
+		/* To handle 1:1 scaling, clear crtc_w/h too. */
+		*crtc_w &= ~1;
+		*crtc_h &= ~1;
+
+		if (*crtc_x < 0 && (*crtc_x & 1))
+			(*crtc_x)++;
+		else
+			*crtc_x &= ~1;
+
+		/* If negative, round up to 0 instead of down */
+		if (*crtc_y < 0 && (*crtc_y & 1))
+			(*crtc_y)++;
+		else
+			*crtc_y &= ~1;
+
+		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
+				*crtc_h, *crtc_x, *crtc_y, fb);
+		ret = igt_display_try_commit_atomic(
+			&data->display,
+			DRM_MODE_ATOMIC_TEST_ONLY |
+				DRM_MODE_ATOMIC_ALLOW_MODESET,
+			NULL);
+		if (!ret)
+			return;
+	}
+
+	igt_assert(!ret || allow_scaling);
+	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
+		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
+
+	*crtc_w = *src_w;
+	*crtc_h = *src_h;
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	igt_display_commit_atomic(&data->display,
+				  DRM_MODE_ATOMIC_TEST_ONLY |
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+				  NULL);
+}
+
+static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
+			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
+			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
+			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
+{
+	cairo_surface_t *surface;
+	cairo_surface_t *clipped_surface;
+	cairo_t *cr;
+
+	surface = igt_get_cairo_surface(data->drm_fd, fb);
+
+	if (src_x || src_y) {
+		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+							     src_w, src_h);
+
+		cr = cairo_create(clipped_surface);
+
+		cairo_translate(cr, -1. * src_x, -1. * src_y);
+
+		cairo_set_source_surface(cr, surface, 0, 0);
+
+		cairo_paint(cr);
+		cairo_surface_flush(clipped_surface);
+
+		cairo_destroy(cr);
+	} else {
+		clipped_surface = surface;
+	}
+
+	cr = cairo_create(result);
+
+	cairo_translate(cr, crtc_x, crtc_y);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
+	}
+
+	cairo_set_source_surface(cr, clipped_surface, 0, 0);
+	cairo_surface_destroy(clipped_surface);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_pattern_set_filter(cairo_get_source(cr),
+					 CAIRO_FILTER_BILINEAR);
+		cairo_pattern_set_extend(cairo_get_source(cr),
+					 CAIRO_EXTEND_NONE);
+	}
+
+	cairo_paint(cr);
+	cairo_surface_flush(result);
+
+	cairo_destroy(cr);
+}
+
+static void prepare_randomized_plane(chamelium_data_t *data,
+				     drmModeModeInfo *mode, igt_plane_t *plane,
+				     struct igt_fb *overlay_fb,
+				     unsigned int index,
+				     cairo_surface_t *result_surface,
+				     bool allow_scaling, bool allow_yuv)
+{
+	struct igt_fb pattern_fb;
+	uint32_t overlay_fb_w, overlay_fb_h;
+	uint32_t overlay_src_w, overlay_src_h;
+	uint32_t overlay_src_x, overlay_src_y;
+	int32_t overlay_crtc_x, overlay_crtc_y;
+	uint32_t overlay_crtc_w, overlay_crtc_h;
+	uint32_t format;
+	uint64_t modifier;
+	size_t stride;
+	bool tiled;
+	int fb_id;
+
+	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
+			      &format, &modifier, allow_yuv);
+
+	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
+	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
+		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
+		  tiled ? "tiled" : "linear");
+
+	/* Get a pattern framebuffer for the overlay plane. */
+	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
+					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
+			       modifier, &stride);
+
+	igt_debug("Plane %d: stride %ld\n", index, stride);
+
+	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
+					   modifier, stride);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_coordinates(data, plane, mode, overlay_fb,
+				    &overlay_src_w, &overlay_src_h,
+				    &overlay_src_x, &overlay_src_y,
+				    &overlay_crtc_w, &overlay_crtc_h,
+				    &overlay_crtc_x, &overlay_crtc_y,
+				    allow_scaling);
+
+	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
+		  overlay_src_h);
+	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
+		  overlay_src_x, overlay_src_y);
+	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
+		  overlay_crtc_h);
+	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
+		  overlay_crtc_y);
+
+	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
+			 overlay_src_x, overlay_src_y, overlay_crtc_w,
+			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
+			 &pattern_fb);
+
+	/* Remove the original pattern framebuffer. */
+	igt_remove_fb(data->drm_fd, &pattern_fb);
+}
+
+static const char test_display_one_mode_desc[] =
+	"Pick the first mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_one_mode(chamelium_data_t *data,
+				  struct chamelium_port *port, uint32_t fourcc,
+				  enum chamelium_check check, int count)
+{
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	igt_output_t *output;
+	igt_plane_t *primary;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	igt_require(igt_plane_has_format_mod(primary, fourcc,
+					     DRM_FORMAT_MOD_LINEAR));
+
+	mode = &connector->modes[0];
+	if (check == CHAMELIUM_CHECK_ANALOG) {
+		bool bridge = chamelium_check_analog_bridge(data, port);
+
+		igt_assert(!(bridge && prune_vga_mode(data, mode)));
+	}
+
+	do_test_display(data, port, output, mode, fourcc, check, count);
+
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_all_modes_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_all_modes(chamelium_data_t *data,
+				   struct chamelium_port *port, uint32_t fourcc,
+				   enum chamelium_check check, int count)
+{
+	bool bridge;
+	int i, count_modes;
+
+	if (check == CHAMELIUM_CHECK_ANALOG)
+		bridge = chamelium_check_analog_bridge(data, port);
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+		igt_require(igt_plane_has_format_mod(primary, fourcc,
+						     DRM_FORMAT_MOD_LINEAR));
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
+		    prune_vga_mode(data, mode))
+			continue;
+
+		do_test_display(data, port, output, mode, fourcc, check, count);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_frame_dump_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then download the captured frames and compare them "
+	"bit-by-bit to the sent ones";
+static void test_display_frame_dump(chamelium_data_t *data,
+				    struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		struct igt_fb fb;
+		struct chamelium_frame_dump *frame;
+		drmModeModeInfo *mode;
+		drmModeConnector *connector;
+		int fb_id, j;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		igt_debug("Reading frame dumps from Chamelium...\n");
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
+		for (j = 0; j < 5; j++) {
+			frame = chamelium_read_captured_frame(data->chamelium,
+							      j);
+			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
+			chamelium_destroy_frame_dump(frame);
+		}
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_aspect_ratio_desc[] =
+	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
+	"check they include the relevant fields";
+static void test_display_aspect_ratio(chamelium_data_t *data,
+				      struct chamelium_port *port)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	int fb_id, i;
+	struct igt_fb fb;
+	bool found, ok;
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_avi infoframe_avi;
+	uint8_t vic = 16; /* TODO: test more VICs */
+	const struct vic_mode *vic_mode;
+	uint32_t aspect_ratio;
+	enum infoframe_avi_picture_aspect_ratio frame_ar;
+
+	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port,
+					  IGT_CUSTOM_EDID_ASPECT_RATIO);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	vic_mode = &vic_modes[vic];
+	aspect_ratio = vic_mode->picture_ar;
+
+	found = false;
+	igt_assert(connector->count_modes > 0);
+	for (i = 0; i < connector->count_modes; i++) {
+		mode = &connector->modes[i];
+
+		if (vic_mode_matches_drm(vic_mode, mode)) {
+			found = true;
+			break;
+		}
+	}
+	igt_assert_f(found,
+		     "Failed to find mode with the correct aspect ratio\n");
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
+						 CHAMELIUM_INFOFRAME_AVI);
+	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
+
+	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
+				 infoframe->payload, infoframe->payload_size);
+	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
+
+	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
+
+	igt_debug("Checking AVI InfoFrame\n");
+	igt_debug("Picture aspect ratio: got %d, expected %d\n",
+		  infoframe_avi.picture_aspect_ratio, frame_ar);
+	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
+		  infoframe_avi.vic, vic);
+
+	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
+	igt_assert(infoframe_avi.vic == vic);
+
+	chamelium_infoframe_destroy(infoframe);
+	igt_remove_fb(data->drm_fd, &fb);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_planes_random_desc[] =
+	"Setup a few overlay planes with random parameters, capture the frame "
+	"and check it matches the expected output";
+static void test_display_planes_random(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum chamelium_check check)
+{
+	igt_output_t *output;
+	drmModeModeInfo *mode;
+	igt_plane_t *primary_plane;
+	struct igt_fb primary_fb;
+	struct igt_fb result_fb;
+	struct igt_fb *overlay_fbs;
+	igt_crc_t *crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
+	unsigned int overlay_planes_max = 0;
+	unsigned int overlay_planes_count;
+	cairo_surface_t *result_surface;
+	int captured_frame_count;
+	bool allow_scaling;
+	bool allow_yuv;
+	unsigned int i;
+	unsigned int fb_id;
+
+	switch (check) {
+	case CHAMELIUM_CHECK_CRC:
+		allow_scaling = false;
+		allow_yuv = false;
+		break;
+	case CHAMELIUM_CHECK_CHECKERBOARD:
+		allow_scaling = true;
+		allow_yuv = true;
+		break;
+	default:
+		igt_assert(false);
+	}
+
+	srand(time(NULL));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Find the connector and pipe. */
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+
+	mode = igt_output_get_mode(output);
+
+	/* Get a framebuffer for the primary plane. */
+	primary_plane =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary_plane);
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
+	igt_assert(fb_id > 0);
+
+	/* Get a framebuffer for the cairo composition result. */
+	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
+			      &result_fb);
+	igt_assert(fb_id > 0);
+
+	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
+
+	/* Paint the primary framebuffer on the result surface. */
+	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
+			 &primary_fb);
+
+	/* Configure the primary plane. */
+	igt_plane_set_fb(primary_plane, &primary_fb);
+
+	overlay_planes_max =
+		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
+
+	/* Limit the number of planes to a reasonable scene. */
+	overlay_planes_max = min(overlay_planes_max, 4u);
+
+	overlay_planes_count = (rand() % overlay_planes_max) + 1;
+	igt_debug("Using %d overlay planes\n", overlay_planes_count);
+
+	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
+
+	for (i = 0; i < overlay_planes_count; i++) {
+		struct igt_fb *overlay_fb = &overlay_fbs[i];
+		igt_plane_t *plane = igt_output_get_plane_type_index(
+			output, DRM_PLANE_TYPE_OVERLAY, i);
+		igt_assert(plane);
+
+		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
+					 result_surface, allow_scaling,
+					 allow_yuv);
+	}
+
+	cairo_surface_destroy(result_surface);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&result_fb);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == 1);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &result_fb, 0);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &result_fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	for (i = 0; i < overlay_planes_count; i++)
+		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
+
+	free(overlay_fbs);
+
+	igt_remove_fb(data->drm_fd, &primary_fb);
+	igt_remove_fb(data->drm_fd, &result_fb);
+}
+
+IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-single", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("dp-crc-fast", DisplayPort)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-multiple", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("dp-frame-dump", DisplayPort)
+			test_display_frame_dump(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-single", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("hdmi-crc-fast", HDMIA)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-multiple", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CRC, 1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-crc-planes-random", HDMIA)
+			test_display_planes_random(&data, port,
+						   CHAMELIUM_CHECK_CRC);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (!igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CHECKERBOARD,
+						1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-cmp-planes-random", HDMIA)
+			test_display_planes_random(
+				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("hdmi-frame-dump", HDMIA)
+			test_display_frame_dump(&data, port);
+
+		igt_describe(test_display_aspect_ratio_desc);
+		connector_subtest("hdmi-aspect-ratio", HDMIA)
+			test_display_aspect_ratio(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("vga-frame-dump", VGA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_ANALOG, 1);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
new file mode 100644
index 00000000..b9544288
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+
+void chamelium_init_test(chamelium_data_t *data)
+{
+	int i;
+
+	/* So fbcon doesn't try to reprobe things itself */
+	kmstest_set_vt_graphics_mode();
+
+	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
+	igt_display_require(&data->display, data->drm_fd);
+	igt_require(data->display.is_atomic);
+
+	/*
+	 * XXX: disabling modeset, can be removed when
+	 * igt_display_require will start doing this for us
+	 */
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	/* we need to initalize chamelium after igt_display_require */
+	data->chamelium = chamelium_init(data->drm_fd, &data->display);
+	igt_require(data->chamelium);
+
+	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
+
+	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
+		data->edids[i] = chamelium_new_edid(data->chamelium,
+						    igt_kms_get_custom_edid(i));
+	}
+}
+
+/* Wait for hotplug and return the remaining time left from timeout */
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
+{
+	struct timespec start, end;
+	int elapsed;
+	bool detected;
+
+	igt_assert_eq(igt_gettime(&start), 0);
+	detected = igt_hotplug_detected(mon, *timeout);
+	igt_assert_eq(igt_gettime(&end), 0);
+
+	elapsed = igt_time_elapsed(&start, &end);
+	igt_assert_lte(0, elapsed);
+	*timeout = max(0, *timeout - elapsed);
+
+	return detected;
+}
+
+/**
+ * chamelium_wait_for_connector_after_hotplug:
+ *
+ * Waits for the connector attached to @port to have a status of @status after
+ * it's plugged/unplugged.
+ *
+ */
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status)
+{
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int hotplug_count = 0;
+
+	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
+		  chamelium_port_get_name(port),
+		  kmstest_connector_status_str(status));
+
+	while (timeout > 0) {
+		if (!chamelium_wait_for_hotplug(mon, &timeout))
+			break;
+
+		hotplug_count++;
+
+		if (chamelium_reprobe_connector(&data->display, data->chamelium,
+						port) == status)
+			return;
+	}
+
+	igt_assert_f(
+		false,
+		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
+		chamelium_port_get_name(port),
+		kmstest_connector_status_str(status),
+		kmstest_connector_status_str(chamelium_reprobe_connector(
+			&data->display, data->chamelium, port)),
+		hotplug_count);
+}
+
+/**
+ * chamelium_port_get_connector:
+ * @data: The Chamelium data instance to use
+ * @port: The chamelium port to prepare its connector
+ * @edid: The chamelium's default EDID has a lot of resolutions, way more then
+ * 		  we need to test. Additionally the default EDID doesn't support
+ *        HDMI audio.
+ *
+ * Makes sure the output display of the connector attached to @port is connected
+ * and ready for use.
+ *
+ * Returns: a pointer to the enabled igt_output_t
+ */
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	/* The chamelium's default EDID has a lot of resolutions, way more then
+	 * we need to test. Additionally the default EDID doesn't support HDMI
+	 * audio.
+	 */
+	chamelium_set_edid(data, port, edid);
+
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_display_reset(display);
+
+	output = chamelium_get_output_for_port(data, port);
+
+	/* Refresh pipe to update connected status */
+	igt_output_set_pipe(output, PIPE_NONE);
+
+	pipe = chamelium_get_pipe_for_output(display, output);
+	igt_output_set_pipe(output, pipe);
+
+	return output;
+}
+
+/**
+ * chamelium_enable_output:
+ *
+ * Modesets the connector attached to @port for the assigned @mode and draws the
+ * @fb.
+ *
+ */
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb)
+{
+	igt_display_t *display = output->display;
+	igt_plane_t *primary =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+
+	igt_assert(primary);
+
+	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
+	igt_plane_set_fb(primary, fb);
+	igt_output_override_mode(output, mode);
+
+	/* Clear any color correction values that might be enabled */
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_GAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
+		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
+					       NULL, 0);
+
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
+		usleep(250000);
+
+	drmModeFreeConnector(connector);
+}
+
+/* Return pipe attached to @outpu.t */
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output)
+{
+	enum pipe pipe;
+
+	for_each_pipe(display, pipe) {
+		if (igt_pipe_connector_valid(pipe, output)) {
+			return pipe;
+		}
+	}
+
+	igt_assert_f(false, "No pipe found for output %s\n",
+		     igt_output_name(output));
+}
+
+static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
+					 size_t height, size_t stride,
+					 size_t block_size)
+{
+	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
+			      0xffffffff };
+	unsigned i, j;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			*(data + i * stride / 4 +
+			  j) = colors[((j / block_size) + (i / block_size)) % 5];
+}
+
+/**
+ * chamelium_get_pattern_fb:
+ *
+ * Creates an @fb with an xr24 pattern and returns the fb_id.
+ *
+ */
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb)
+{
+	int fb_id;
+	void *ptr;
+
+	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
+
+	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
+			      DRM_FORMAT_MOD_LINEAR, fb);
+	igt_assert(fb_id > 0);
+
+	ptr = igt_fb_map_buffer(fb->fd, fb);
+	igt_assert(ptr);
+
+	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
+				     block_size);
+	igt_fb_unmap_buffer(fb, ptr);
+
+	return fb_id;
+}
+
+/* Generate a simple @fb for the size of @mode. */
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode)
+{
+	int fb_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, fb);
+
+	igt_assert(fb_id > 0);
+}
+
+/* Returns the first preferred mode for the connector attached to @port. */
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(chamelium, port, false);
+	drmModeModeInfo mode;
+	igt_assert(&connector->modes[0] != NULL);
+	memcpy(&mode, &connector->modes[0], sizeof(mode));
+	drmModeFreeConnector(connector);
+	return mode;
+}
+
+/* Returns the igt display output for the connector attached to @port. */
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, true);
+	igt_output_t *output =
+		igt_output_from_connector(&data->display, connector);
+	drmModeFreeConnector(connector);
+	igt_assert(output != NULL);
+	return output;
+}
+
+/* Set the EDID of index @edid to Chamelium's @port. */
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid)
+{
+	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
+}
+
+/**
+ * chamelium_check_analog_bridge:
+ *
+ * Check if the connector associalted to @port is an analog bridge by checking
+ * if it has its own EDID.
+ *
+ */
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+	uint64_t edid_blob_id;
+	const struct edid *edid;
+	char edid_vendor[3];
+
+	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
+		drmModeFreeConnector(connector);
+		return false;
+	}
+
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	edid = (const struct edid *)edid_blob->data;
+	edid_get_mfg(edid, edid_vendor);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+
+	/* Analog bridges provide their own EDID */
+	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
+	    edid_vendor[2] != 'T')
+		return true;
+
+	return false;
+}
\ No newline at end of file
diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
new file mode 100644
index 00000000..09fa4829
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+
+#include "igt.h"
+
+#define ONLINE_TIMEOUT 20 /* seconds */
+
+#define for_each_port(p, port)                                 \
+	for (p = 0, port = data.ports[p]; p < data.port_count; \
+	     p++, port = data.ports[p])
+
+#define connector_subtest(name__, type__)                           \
+	igt_subtest(name__)                                         \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+/*
+ * The chamelium data structure is used to store all the information known about
+ * chamelium to run the tests.
+ */
+typedef struct {
+	struct chamelium *chamelium;
+	struct chamelium_port **ports;
+	igt_display_t display;
+	int port_count;
+
+	int drm_fd;
+
+	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
+} chamelium_data_t;
+
+void chamelium_init_test(chamelium_data_t *data);
+
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status);
+
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid);
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb);
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output);
+
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb);
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode);
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port);
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port);
+
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid);
+
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port);
+
+#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
new file mode 100644
index 00000000..8a4e1aba
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_hpd.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the HPD functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "kms_chamelium_helper.h"
+
+#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
+#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
+
+#define HPD_TOGGLE_COUNT_VGA 5
+#define HPD_TOGGLE_COUNT_DP_HDMI 15
+#define HPD_TOGGLE_COUNT_FAST 3
+
+enum test_modeset_mode {
+	TEST_MODESET_ON,
+	TEST_MODESET_ON_OFF,
+	TEST_MODESET_OFF,
+};
+
+static void try_suspend_resume_hpd(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   enum igt_suspend_state state,
+				   enum igt_suspend_test test,
+				   struct udev_monitor *mon, bool connected)
+{
+	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
+						     DRM_MODE_CONNECTED;
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int delay;
+	int p;
+
+	igt_flush_uevents(mon);
+
+	delay = igt_get_autoresume_delay(state) * 1000 / 2;
+
+	if (port) {
+		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
+					      !connected);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			port = data->ports[p];
+			chamelium_schedule_hpd_toggle(data->chamelium, port,
+						      delay, !connected);
+		}
+
+		port = NULL;
+	}
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	if (port) {
+		igt_assert_eq(chamelium_reprobe_connector(
+				      &data->display, data->chamelium, port),
+			      target_state);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			drmModeConnection current_state;
+
+			port = data->ports[p];
+			/*
+			 * There could be as many hotplug events sent by
+			 * driver as connectors we scheduled an HPD toggle on
+			 * above, depending on timing. So if we're not seeing
+			 * the expected connector state try to wait for an HPD
+			 * event for each connector/port.
+			 */
+			current_state = chamelium_reprobe_connector(
+				&data->display, data->chamelium, port);
+			if (p > 0 && current_state != target_state) {
+				igt_assert(chamelium_wait_for_hotplug(
+					mon, &timeout));
+				current_state = chamelium_reprobe_connector(
+					&data->display, data->chamelium, port);
+			}
+
+			igt_assert_eq(current_state, target_state);
+		}
+
+		port = NULL;
+	}
+}
+
+static const char test_basic_hotplug_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug";
+static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
+			 int toggle_count, enum test_modeset_mode modeset_mode)
+{
+	int i;
+	enum pipe pipe;
+	struct igt_fb fb = { 0 };
+	drmModeModeInfo mode;
+	struct udev_monitor *mon = igt_watch_uevents();
+	igt_output_t *output = chamelium_get_output_for_port(data, port);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+
+	for (i = 0; i < toggle_count; i++) {
+		igt_flush_uevents(mon);
+
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF ||
+		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
+			if (i == 0) {
+				/* We can only get mode and pipe once we are
+				 * connected */
+				output = chamelium_get_output_for_port(data,
+								       port);
+				pipe = chamelium_get_pipe_for_output(
+					&data->display, output);
+				mode = chamelium_get_mode_for_port(
+					data->chamelium, port);
+				chamelium_create_fb_for_mode(data, &fb, &mode);
+			}
+
+			igt_output_set_pipe(output, pipe);
+			chamelium_enable_output(data, port, output, &mode, &fb);
+		}
+
+		/* Now check if we get a hotplug from disconnection */
+		chamelium_unplug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF) {
+			igt_output_set_pipe(output, PIPE_NONE);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static const char test_hotplug_for_each_pipe_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug for each pipe with valid output";
+static void test_hotplug_for_each_pipe(chamelium_data_t *data,
+				       struct chamelium_port *port)
+{
+	igt_output_t *output;
+	enum pipe pipe;
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	/* Disconnect if any port got connected */
+	chamelium_unplug(data->chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_DISCONNECTED);
+
+	for_each_pipe(&data->display, pipe) {
+		igt_flush_uevents(mon);
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+		output = chamelium_get_output_for_port(data, port);
+
+		/* If pipe is valid for output then set it */
+		if (igt_pipe_connector_valid(pipe, output)) {
+			igt_output_set_pipe(output, pipe);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+
+		chamelium_unplug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+		igt_flush_uevents(mon);
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_suspend_resume_hpd_desc[] =
+	"Toggle HPD during suspend, check that uevents are sent and connector "
+	"status is updated";
+static void test_suspend_resume_hpd(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_suspend_state state,
+				    enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_suspend_resume_hpd_common_desc[] =
+	"Toggle HPD during suspend on all connectors, check that uevents are "
+	"sent and connector status is updated";
+static void test_suspend_resume_hpd_common(chamelium_data_t *data,
+					   enum igt_suspend_state state,
+					   enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	struct chamelium_port *port;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		port = data->ports[p];
+		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_without_ddc_desc[] =
+	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
+static void test_hpd_without_ddc(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+	igt_flush_uevents(mon);
+
+	/* Disable the DDC on the connector and make sure we still get a
+	 * hotplug
+	 */
+	chamelium_port_set_ddc_state(data->chamelium, port, false);
+	chamelium_plug(data->chamelium, port);
+
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_assert_eq(chamelium_reprobe_connector(&data->display,
+						  data->chamelium, port),
+		      DRM_MODE_CONNECTED);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_storm_detect_desc[] =
+	"Trigger a series of hotplugs in a very small timeframe to simulate a"
+	"bad cable, check the kernel falls back to polling to avoid a hotplug "
+	"storm";
+static void test_hpd_storm_detect(chamelium_data_t *data,
+				  struct chamelium_port *port, int width)
+{
+	struct udev_monitor *mon;
+	int count = 0;
+
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 1);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(igt_hpd_storm_detected(data->drm_fd));
+
+	mon = igt_watch_uevents();
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+
+	/*
+	 * Polling should have been enabled by the HPD storm at this point,
+	 * so we should only get at most 1 hotplug event
+	 */
+	igt_until_timeout(5)
+		count += igt_hotplug_detected(mon, 1);
+	igt_assert_lt(count, 2);
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_hpd_storm_disable_desc[] =
+	"Disable HPD storm detection, trigger a storm and check the kernel "
+	"doesn't detect one";
+static void test_hpd_storm_disable(chamelium_data_t *data,
+				   struct chamelium_port *port, int width)
+{
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
+
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-suspend", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("dp-hpd-storm", DisplayPort)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_DP);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("dp-hpd-storm-disable", DisplayPort)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_DP);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("hdmi-hpd-storm", HDMIA)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_HDMI);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_HDMI);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-enable-disable-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-with-enabled-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-suspend", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-hibernate", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_without_ddc_desc);
+		connector_subtest("vga-hpd-without-ddc", VGA)
+			test_hpd_without_ddc(&data, port);
+	}
+
+	igt_describe("Tests that operate on all connectors");
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(data.port_count);
+		}
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-suspend")
+			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
+						       SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-hibernate")
+			test_suspend_resume_hpd_common(&data,
+						       SUSPEND_STATE_DISK,
+						       SUSPEND_TEST_DEVICES);
+	}
+
+	igt_describe(test_hotplug_for_each_pipe_desc);
+	connector_subtest("vga-hpd-for-each-pipe", VGA)
+		test_hotplug_for_each_pipe(&data, port);
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 0d307730..6e5cc436 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
 # is too costly in comparison to the value
 # provided.
 ###############################################
-igt@kms_chamelium@hdmi-.*-planes-random
+igt@kms_chamelium_frames@hdmi-.*-planes-random
 ###############################################
 # Broadcom
 ###############################################
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index f57f8ff3..fb4c0f73 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
 igt@kms_addfb_basic@unused-offsets
 igt@kms_addfb_basic@unused-pitches
 igt@kms_busy@basic
-igt@kms_chamelium@dp-hpd-fast
-igt@kms_chamelium@dp-edid-read
-igt@kms_chamelium@dp-crc-fast
-igt@kms_chamelium@hdmi-hpd-fast
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@vga-hpd-fast
-igt@kms_chamelium@vga-edid-read
+igt@kms_chamelium_hpd@dp-hpd-fast
+igt@kms_chamelium_edid@dp-edid-read
+igt@kms_chamelium_frames@dp-crc-fast
+igt@kms_chamelium_hpd@hdmi-hpd-fast
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_hpd@vga-hpd-fast
+igt@kms_chamelium_edid@vga-edid-read
 igt@kms_prop_blob@basic
 igt@kms_cursor_legacy@basic-busy-flip-before-cursor
 igt@kms_cursor_legacy@basic-flip-after-cursor
@@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
 igt@i915_suspend@basic-s3-without-i915
 igt@gem_exec_suspend@basic-s0
 igt@gem_exec_suspend@basic-s3
-igt@kms_chamelium@common-hpd-after-suspend
+igt@kms_chamelium_hpd@common-hpd-after-suspend
 igt@kms_pipe_crc_basic@suspend-read-crc
diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
index f0ae30e3..f9242232 100644
--- a/tests/kms_color_helper.h
+++ b/tests/kms_color_helper.h
@@ -27,7 +27,7 @@
 
 /*
  * This header is for code that is shared between kms_color.c and
- * kms_color_chamelium.c. Reusability elsewhere can be questionable.
+ * kms_chamelium_color.c. Reusability elsewhere can be questionable.
  */
 
 #include <math.h>
diff --git a/tests/meson.build b/tests/meson.build
index 5c052e73..b52399d5 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -260,7 +260,10 @@ msm_progs = [
 ]
 
 chamelium_progs = [
-	'kms_chamelium',
+	'kms_chamelium_audio',
+	'kms_chamelium_edid',
+	'kms_chamelium_frames',
+	'kms_chamelium_hpd',
 ]
 
 test_deps = [ igt_deps ]
@@ -309,7 +312,8 @@ endforeach
 if chamelium.found()
 	foreach prog : chamelium_progs
 		test_executables += executable(prog,
-				 join_paths('chamelium', prog + '.c'),
+				 [join_paths('chamelium', prog + '.c'), 
+				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
 				 dependencies : test_deps,
 				 install_dir : libexecdir,
 				 install_rpath : libexecdir_rpathdir,
@@ -436,13 +440,13 @@ test_executables += executable('kms_color',
 test_list += 'kms_color'
 
 if chamelium.found()
-       test_executables += executable('kms_color_chamelium',
-                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
+       test_executables += executable('kms_chamelium_color',
+                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
                              dependencies : test_deps + [ chamelium ],
                              install_dir : libexecdir,
                              install_rpath : libexecdir_rpathdir,
                              install : true)
-       test_list += 'kms_color_chamelium'
+       test_list += 'kms_chamelium_color'
 endif
 
 test_executables += executable('sw_sync', 'sw_sync.c',
diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
index dd45d12a..a5521021 100644
--- a/tests/vc4_ci/vc4-chamelium-fast.testlist
+++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
@@ -1,14 +1,14 @@
-igt@kms_chamelium@hdmi-crc-abgr8888
-igt@kms_chamelium@hdmi-crc-argb1555
-igt@kms_chamelium@hdmi-crc-argb8888
-igt@kms_chamelium@hdmi-crc-bgr565
-igt@kms_chamelium@hdmi-crc-bgr888
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@hdmi-crc-rgb565
-igt@kms_chamelium@hdmi-crc-rgb888
-igt@kms_chamelium@hdmi-crc-xbgr8888
-igt@kms_chamelium@hdmi-crc-xrgb1555
-igt@kms_chamelium@hdmi-crc-xrgb8888
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-hpd
-igt@kms_chamelium@hdmi-hpd-fast
+igt@kms_chamelium_frames@hdmi-crc-abgr8888
+igt@kms_chamelium_frames@hdmi-crc-argb1555
+igt@kms_chamelium_frames@hdmi-crc-argb8888
+igt@kms_chamelium_frames@hdmi-crc-bgr565
+igt@kms_chamelium_frames@hdmi-crc-bgr888
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_frames@hdmi-crc-rgb565
+igt@kms_chamelium_frames@hdmi-crc-rgb888
+igt@kms_chamelium_frames@hdmi-crc-xbgr8888
+igt@kms_chamelium_frames@hdmi-crc-xrgb1555
+igt@kms_chamelium_frames@hdmi-crc-xrgb8888
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_hpd@hdmi-hpd
+igt@kms_chamelium_hpd@hdmi-hpd-fast
-- 
2.38.1.584.g0f3c55d4c2-goog

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (4 preceding siblings ...)
  2022-12-01 16:29 ` [igt-dev] [PATCH v2] " Mark Yacoub
@ 2022-12-01 18:13 ` Patchwork
  2022-12-01 18:44 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-01 18:13 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
URL   : https://patchwork.freedesktop.org/series/111501/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/752655 for the overview.

build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808705):
  ../tests/chamelium/kms_chamelium_edid.c:145:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
         drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
         ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    do { if (!(expr)) \
               ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:144:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    igt_assert(edid_blob =
                         ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    do { if (!(expr)) \
               ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669917860:step_script
  section_start:1669917860:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917860:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808700):
  ../tests/chamelium/kms_chamelium_edid.c:145:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    145 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:144:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669917871:step_script
  section_start:1669917871:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917871:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808704):
          uint32_t bpp;
          ^
  /usr/include/xf86drmMode.h:221:2: error: unknown type name 'uint32_t'
          uint32_t depth;
          ^
  /usr/include/xf86drmMode.h:223:2: error: unknown type name 'uint32_t'
          uint32_t handle;
          ^
  /usr/include/xf86drmMode.h:229:2: error: unknown type name 'uint32_t'
          uint32_t id;
          ^
  fatal error: too many errors emitted, stopping now [-ferror-limit=]
  20 errors generated.
  ninja: build stopped: subcommand failed.
  section_end:1669917933:step_script
  section_start:1669917933:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917934:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808703):
  ../tests/chamelium/kms_chamelium_edid.c:145:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    145 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:144:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669917870:step_script
  section_start:1669917870:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917871:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808701):
  ../tests/chamelium/kms_chamelium_edid.c:145:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    145 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:144:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669917855:step_script
  section_start:1669917855:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917856:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/32808702):
  ../tests/chamelium/kms_chamelium_edid.c:145:7: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
    145 |       drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
        |       ^~~~~~~~~~~~~~~~~~~~~~
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  ../tests/chamelium/kms_chamelium_edid.c:144:23: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  igt_assert(edid_blob =
        |                       ^
  ../lib/igt_core.h:676:13: note: in definition of macro ‘igt_assert’
    676 |  do { if (!(expr)) \
        |             ^~~~
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1669917863:step_script
  section_start:1669917863:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1669917863:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/752655

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (5 preceding siblings ...)
  2022-12-01 18:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2) Patchwork
@ 2022-12-01 18:44 ` Patchwork
  2022-12-02  8:02 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-01 18:44 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 18536 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
URL   : https://patchwork.freedesktop.org/series/111501/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12460 -> IGTPW_8182
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html

Participating hosts (43 -> 34)
------------------------------

  Additional (2): fi-tgl-dsi bat-dg1-6 
  Missing    (11): fi-kbl-soraka fi-ilk-m540 bat-kbl-2 fi-bsw-n3050 bat-dg1-5 bat-dg2-8 bat-dg2-9 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8182:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - {bat-jsl-1}:        NOTRUN -> [SKIP][1] +8 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {fi-jsl-1}:         NOTRUN -> [SKIP][2] +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-adl-ddr5:        NOTRUN -> [SKIP][3] +8 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {fi-ehl-2}:         NOTRUN -> [SKIP][4] +8 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - {bat-adlm-1}:       NOTRUN -> [SKIP][5] +8 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adlm-1/igt@kms_chamelium_frames@dp-crc-fast.html
    - {bat-rplp-1}:       NOTRUN -> [SKIP][6] +8 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - bat-adlp-4:         NOTRUN -> [SKIP][7] +7 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adlp-4/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - {bat-adln-1}:       NOTRUN -> [SKIP][8] +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - {bat-rpls-2}:       NOTRUN -> [SKIP][9] +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-rpls-2/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-rkl-guc:         NOTRUN -> [SKIP][10] +8 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-rkl-guc/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - bat-dg1-6:          NOTRUN -> [SKIP][11] +8 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - {bat-adlp-6}:       NOTRUN -> [SKIP][12] +8 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adlp-6/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - fi-rkl-11600:       NOTRUN -> [SKIP][13] +7 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - {fi-tgl-dsi}:       NOTRUN -> [SKIP][14] +7 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-tgl-dsi/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-icl-u2:          NOTRUN -> [SKIP][15] +8 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12460 and IGTPW_8182:

### New IGT tests (9) ###

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 1 pass(s) 28 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 34 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 34 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8182 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - fi-rkl-11600:       [PASS][16] -> [INCOMPLETE][17] ([i915#6179])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/fi-rkl-11600/igt@gem_exec_suspend@basic-s3@smem.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-rkl-11600/igt@gem_exec_suspend@basic-s3@smem.html

  * igt@gem_mmap@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][18] ([i915#4083])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@gem_mmap@basic.html

  * igt@gem_render_tiled_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][19] ([i915#4079]) +1 similar issue
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@gem_render_tiled_blits@basic.html

  * igt@gem_tiled_fence_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][20] ([i915#4077]) +2 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html

  * igt@i915_pm_backlight@basic-brightness:
    - bat-dg1-6:          NOTRUN -> [SKIP][21] ([i915#7561])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html

  * igt@i915_pm_rps@basic-api:
    - bat-dg1-6:          NOTRUN -> [SKIP][22] ([i915#6621])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@i915_pm_rps@basic-api.html

  * igt@i915_selftest@live@migrate:
    - bat-adlp-4:         [PASS][23] -> [INCOMPLETE][24] ([i915#7308] / [i915#7348])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/bat-adlp-4/igt@i915_selftest@live@migrate.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adlp-4/igt@i915_selftest@live@migrate.html

  * igt@i915_suspend@basic-s3-without-i915:
    - fi-rkl-11600:       [PASS][25] -> [FAIL][26] ([fdo#103375])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/fi-rkl-11600/igt@i915_suspend@basic-s3-without-i915.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-rkl-11600/igt@i915_suspend@basic-s3-without-i915.html

  * igt@kms_addfb_basic@basic-y-tiled-legacy:
    - bat-dg1-6:          NOTRUN -> [SKIP][27] ([i915#4215])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html

  * igt@kms_addfb_basic@tile-pitch-mismatch:
    - bat-dg1-6:          NOTRUN -> [SKIP][28] ([i915#4212]) +7 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - fi-ilk-650:         NOTRUN -> [SKIP][29] ([fdo#109271]) +8 similar issues
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-ilk-650/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-cfl-guc:         NOTRUN -> [SKIP][30] ([fdo#109271]) +8 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html
    - fi-glk-dsi:         NOTRUN -> [SKIP][31] ([fdo#109271]) +8 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-glk-dsi/igt@kms_chamelium_edid@hdmi-edid-read.html
    - fi-pnv-d510:        NOTRUN -> [SKIP][32] ([fdo#109271]) +8 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-pnv-d510/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - fi-hsw-4770:        NOTRUN -> [SKIP][33] ([fdo#109271]) +8 similar issues
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-hsw-4770/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-cfl-8109u:       NOTRUN -> [SKIP][34] ([fdo#109271]) +8 similar issues
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][35] ([fdo#109271]) +8 similar issues
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][36] ([fdo#109271]) +7 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][37] ([fdo#109271]) +8 similar issues
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-ivb-3770/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][38] ([fdo#109271]) +8 similar issues
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-elk-e7500/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - fi-glk-j4005:       NOTRUN -> [SKIP][39] ([fdo#109271]) +8 similar issues
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-snb-2600:        NOTRUN -> [SKIP][40] ([fdo#109271]) +8 similar issues
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-skl-guc:         NOTRUN -> [SKIP][41] ([fdo#109271]) +8 similar issues
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-skl-guc/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - fi-cfl-8700k:       NOTRUN -> [SKIP][42] ([fdo#109271]) +8 similar issues
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-cfl-8700k/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
    - fi-blb-e6850:       NOTRUN -> [SKIP][43] ([fdo#109271]) +8 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-apl-guc:         NOTRUN -> [SKIP][44] ([fdo#109271]) +8 similar issues
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][45] ([fdo#109271]) +7 similar issues
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][46] ([fdo#109271]) +8 similar issues
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-skl-6700k2:      NOTRUN -> [SKIP][47] ([fdo#109271]) +4 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-skl-6700k2/igt@kms_chamelium_hpd@vga-hpd-fast.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
    - bat-dg1-6:          NOTRUN -> [SKIP][48] ([i915#4103] / [i915#4213])
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html

  * igt@kms_force_connector_basic@force-load-detect:
    - bat-dg1-6:          NOTRUN -> [SKIP][49] ([fdo#109285])
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_psr@sprite_plane_onoff:
    - bat-dg1-6:          NOTRUN -> [SKIP][50] ([i915#1072] / [i915#4078]) +3 similar issues
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - bat-dg1-6:          NOTRUN -> [SKIP][51] ([i915#3555])
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@prime_vgem@basic-gtt:
    - bat-dg1-6:          NOTRUN -> [SKIP][52] ([i915#3708] / [i915#4077]) +1 similar issue
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@prime_vgem@basic-gtt.html

  * igt@prime_vgem@basic-read:
    - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#3708]) +3 similar issues
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@prime_vgem@basic-read.html

  * igt@prime_vgem@basic-userptr:
    - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#3708] / [i915#4873])
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-dg1-6/igt@prime_vgem@basic-userptr.html

  * igt@runner@aborted:
    - bat-adlp-4:         NOTRUN -> [FAIL][55] ([i915#4312])
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-adlp-4/igt@runner@aborted.html

  
#### Possible fixes ####

  * igt@i915_selftest@live@gt_pm:
    - {bat-rpls-2}:       [DMESG-FAIL][56] ([i915#4258]) -> [PASS][57]
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/bat-rpls-2/igt@i915_selftest@live@gt_pm.html
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-rpls-2/igt@i915_selftest@live@gt_pm.html

  * igt@i915_selftest@live@reset:
    - {bat-rpls-2}:       [DMESG-FAIL][58] ([i915#4983]) -> [PASS][59]
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/bat-rpls-2/igt@i915_selftest@live@reset.html
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/bat-rpls-2/igt@i915_selftest@live@reset.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor@atomic-transitions-varying-size:
    - fi-bsw-kefka:       [FAIL][60] ([i915#6298]) -> [PASS][61]
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/fi-bsw-kefka/igt@kms_cursor_legacy@basic-busy-flip-before-cursor@atomic-transitions-varying-size.html
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-bsw-kefka/igt@kms_cursor_legacy@basic-busy-flip-before-cursor@atomic-transitions-varying-size.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor@varying-size:
    - fi-bsw-kefka:       [FAIL][62] -> [PASS][63]
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/fi-bsw-kefka/igt@kms_cursor_legacy@basic-busy-flip-before-cursor@varying-size.html
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/fi-bsw-kefka/igt@kms_cursor_legacy@basic-busy-flip-before-cursor@varying-size.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103375]: https://bugs.freedesktop.org/show_bug.cgi?id=103375
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1759]: https://gitlab.freedesktop.org/drm/intel/issues/1759
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
  [i915#4258]: https://gitlab.freedesktop.org/drm/intel/issues/4258
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
  [i915#6179]: https://gitlab.freedesktop.org/drm/intel/issues/6179
  [i915#6298]: https://gitlab.freedesktop.org/drm/intel/issues/6298
  [i915#6367]: https://gitlab.freedesktop.org/drm/intel/issues/6367
  [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
  [i915#6559]: https://gitlab.freedesktop.org/drm/intel/issues/6559
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6949]: https://gitlab.freedesktop.org/drm/intel/issues/6949
  [i915#6997]: https://gitlab.freedesktop.org/drm/intel/issues/6997
  [i915#7058]: https://gitlab.freedesktop.org/drm/intel/issues/7058
  [i915#7308]: https://gitlab.freedesktop.org/drm/intel/issues/7308
  [i915#7346]: https://gitlab.freedesktop.org/drm/intel/issues/7346
  [i915#7348]: https://gitlab.freedesktop.org/drm/intel/issues/7348
  [i915#7433]: https://gitlab.freedesktop.org/drm/intel/issues/7433
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7078 -> IGTPW_8182

  CI-20190529: 20190529
  CI_DRM_12460: 0b96883d5e7a2baa9f75d50656e722c61d96c08f @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8182: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html
  IGT_7078: 71bce31c26998d5d53cff3138049261fd6c4fbaf @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git


Testlist changes
----------------

+++ 71 lines
--- 71 lines

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html

[-- Attachment #2: Type: text/html, Size: 21021 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ Fi.CI.IGT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (6 preceding siblings ...)
  2022-12-01 18:44 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
@ 2022-12-02  8:02 ` Patchwork
  2022-12-06 19:19 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3) Patchwork
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-02  8:02 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 50580 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2)
URL   : https://patchwork.freedesktop.org/series/111501/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_12460_full -> IGTPW_8182_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_8182_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_8182_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html

Participating hosts (11 -> 10)
------------------------------

  Additional (2): shard-rkl shard-dg1 
  Missing    (3): pig-skl-6260u pig-kbl-iris pig-glk-j5005 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8182_full:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium_audio@dp-audio} (NEW):
    - {shard-tglu-10}:    NOTRUN -> [SKIP][1] +13 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglu-10/igt@kms_chamelium_audio@dp-audio.html

  * {igt@kms_chamelium_audio@hdmi-audio-edid} (NEW):
    - {shard-dg1}:        NOTRUN -> [SKIP][2] +41 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-dg1-18/igt@kms_chamelium_audio@hdmi-audio-edid.html

  * {igt@kms_chamelium_edid@hdmi-edid-stress-resolution-4k} (NEW):
    - {shard-tglu}:       NOTRUN -> [SKIP][3] +27 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglu-3/igt@kms_chamelium_edid@hdmi-edid-stress-resolution-4k.html

  * {igt@kms_chamelium_hpd@dp-hpd-storm} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][4] +49 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb6/igt@kms_chamelium_hpd@dp-hpd-storm.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - {shard-rkl}:        NOTRUN -> [SKIP][5] +42 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-rkl-4/igt@kms_chamelium_hpd@vga-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][6] +48 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode.html

  * igt@perf_pmu@busy-accuracy-2@vcs0:
    - shard-glk:          [PASS][7] -> [INCOMPLETE][8]
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk4/igt@perf_pmu@busy-accuracy-2@vcs0.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk3/igt@perf_pmu@busy-accuracy-2@vcs0.html

  
#### Suppressed ####

  The following results come from untrusted machines, tests, or statuses.
  They do not affect the overall result.

  * {igt@v3d/v3d_perfmon@get-values-invalid-perfmon}:
    - {shard-dg1}:        NOTRUN -> [SKIP][9] +13 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-dg1-13/igt@v3d/v3d_perfmon@get-values-invalid-perfmon.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12460_full and IGTPW_8182_full:

### New IGT tests (63) ###

  * igt@kms_chamelium_audio@dp-audio:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@dp-audio-edid:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio-edid:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-25:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-50:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-75:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-blue-to-red:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-green-to-red:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-limited-range:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-max:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-negative:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-red-to-blue:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@degamma:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@gamma:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-change-during-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-resolution-list:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-non-4k:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-mode-timings:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-change-during-suspend:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-non-4k:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-mode-timings:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-single:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-frame-dump:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-aspect-ratio:
    - Statuses : 1 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-cmp-planar-formats:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-nonplanar-formats:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-single:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-frame-dump:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@vga-frame-dump:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-after-suspend:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-enable-disable-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-for-each-pipe:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm-disable:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-with-enabled-mode:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd:
    - Statuses : 2 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-after-suspend:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-enable-disable-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-for-each-pipe:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm-disable:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-with-enabled-mode:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-after-suspend:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-enable-disable-mode:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-for-each-pipe:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode:
    - Statuses : 8 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-without-ddc:
    - Statuses : 7 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8182_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@drm_buddy@all:
    - shard-tglb:         NOTRUN -> [SKIP][10] ([i915#6433])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@drm_buddy@all.html

  * igt@gem_ccs@suspend-resume:
    - shard-tglb:         NOTRUN -> [SKIP][11] ([i915#5325])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@gem_ccs@suspend-resume.html

  * igt@gem_create@create-massive:
    - shard-tglb:         NOTRUN -> [DMESG-WARN][12] ([i915#4991])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@gem_create@create-massive.html

  * igt@gem_exec_balancer@parallel-bb-first:
    - shard-iclb:         [PASS][13] -> [SKIP][14] ([i915#4525])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb1/igt@gem_exec_balancer@parallel-bb-first.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@gem_exec_balancer@parallel-bb-first.html

  * igt@gem_exec_endless@dispatch@vcs1:
    - shard-tglb:         [PASS][15] -> [TIMEOUT][16] ([i915#3778])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb3/igt@gem_exec_endless@dispatch@vcs1.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@gem_exec_endless@dispatch@vcs1.html

  * igt@gem_exec_fair@basic-none-vip@rcs0:
    - shard-tglb:         NOTRUN -> [FAIL][17] ([i915#2842]) +1 similar issue
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@gem_exec_fair@basic-none-vip@rcs0.html

  * igt@gem_exec_fair@basic-none@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][18] ([i915#2842])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb1/igt@gem_exec_fair@basic-none@vcs1.html

  * igt@gem_exec_fair@basic-throttle@rcs0:
    - shard-glk:          [PASS][19] -> [FAIL][20] ([i915#2842]) +2 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk5/igt@gem_exec_fair@basic-throttle@rcs0.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk9/igt@gem_exec_fair@basic-throttle@rcs0.html

  * igt@gem_exec_params@rsvd2-dirt:
    - shard-tglb:         NOTRUN -> [SKIP][21] ([fdo#109283])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@gem_exec_params@rsvd2-dirt.html

  * igt@gem_lmem_swapping@parallel-multi:
    - shard-apl:          NOTRUN -> [SKIP][22] ([fdo#109271] / [i915#4613])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl2/igt@gem_lmem_swapping@parallel-multi.html
    - shard-iclb:         NOTRUN -> [SKIP][23] ([i915#4613])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb1/igt@gem_lmem_swapping@parallel-multi.html

  * igt@gem_lmem_swapping@random:
    - shard-tglb:         NOTRUN -> [SKIP][24] ([i915#4613]) +3 similar issues
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb5/igt@gem_lmem_swapping@random.html

  * igt@gem_pxp@display-protected-crc:
    - shard-tglb:         NOTRUN -> [SKIP][25] ([i915#4270])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb3/igt@gem_pxp@display-protected-crc.html
    - shard-iclb:         NOTRUN -> [SKIP][26] ([i915#4270])
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@gem_pxp@display-protected-crc.html

  * igt@gem_render_copy@y-tiled-ccs-to-y-tiled-mc-ccs:
    - shard-iclb:         NOTRUN -> [SKIP][27] ([i915#768])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@gem_render_copy@y-tiled-ccs-to-y-tiled-mc-ccs.html

  * igt@gem_softpin@evict-snoop-interruptible:
    - shard-tglb:         NOTRUN -> [SKIP][28] ([fdo#109312])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@gem_softpin@evict-snoop-interruptible.html

  * igt@gem_userptr_blits@access-control:
    - shard-tglb:         NOTRUN -> [SKIP][29] ([i915#3297])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@gem_userptr_blits@access-control.html

  * igt@gen9_exec_parse@allowed-single:
    - shard-apl:          [PASS][30] -> [DMESG-WARN][31] ([i915#5566] / [i915#716])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-apl1/igt@gen9_exec_parse@allowed-single.html
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl3/igt@gen9_exec_parse@allowed-single.html
    - shard-glk:          [PASS][32] -> [DMESG-WARN][33] ([i915#5566] / [i915#716])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk7/igt@gen9_exec_parse@allowed-single.html
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk5/igt@gen9_exec_parse@allowed-single.html

  * igt@gen9_exec_parse@bb-start-far:
    - shard-iclb:         NOTRUN -> [SKIP][34] ([i915#2856])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@gen9_exec_parse@bb-start-far.html
    - shard-tglb:         NOTRUN -> [SKIP][35] ([i915#2527] / [i915#2856]) +1 similar issue
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@gen9_exec_parse@bb-start-far.html

  * igt@i915_pm_dc@dc6-psr:
    - shard-iclb:         [PASS][36] -> [FAIL][37] ([i915#3989] / [i915#454])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb6/igt@i915_pm_dc@dc6-psr.html
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@i915_pm_dc@dc6-psr.html

  * igt@i915_pm_dc@dc9-dpms:
    - shard-iclb:         [PASS][38] -> [SKIP][39] ([i915#4281])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb8/igt@i915_pm_dc@dc9-dpms.html
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@i915_pm_dc@dc9-dpms.html

  * igt@i915_pm_rpm@dpms-mode-unset-non-lpsp:
    - shard-iclb:         NOTRUN -> [SKIP][40] ([fdo#110892])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb8/igt@i915_pm_rpm@dpms-mode-unset-non-lpsp.html

  * igt@i915_pm_rpm@modeset-non-lpsp:
    - shard-tglb:         NOTRUN -> [SKIP][41] ([fdo#111644] / [i915#1397] / [i915#2411]) +1 similar issue
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb5/igt@i915_pm_rpm@modeset-non-lpsp.html

  * igt@kms_big_fb@4-tiled-8bpp-rotate-270:
    - shard-tglb:         NOTRUN -> [SKIP][42] ([i915#5286]) +3 similar issues
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_big_fb@4-tiled-8bpp-rotate-270.html
    - shard-iclb:         NOTRUN -> [SKIP][43] ([i915#5286]) +1 similar issue
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb5/igt@kms_big_fb@4-tiled-8bpp-rotate-270.html

  * igt@kms_big_fb@y-tiled-64bpp-rotate-270:
    - shard-tglb:         NOTRUN -> [SKIP][44] ([fdo#111614]) +1 similar issue
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@kms_big_fb@y-tiled-64bpp-rotate-270.html

  * igt@kms_big_fb@yf-tiled-64bpp-rotate-270:
    - shard-tglb:         NOTRUN -> [SKIP][45] ([fdo#111615]) +2 similar issues
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@kms_big_fb@yf-tiled-64bpp-rotate-270.html

  * igt@kms_big_joiner@2x-modeset:
    - shard-tglb:         NOTRUN -> [SKIP][46] ([i915#2705])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@kms_big_joiner@2x-modeset.html

  * igt@kms_ccs@pipe-a-bad-pixel-format-y_tiled_gen12_mc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][47] ([i915#3689] / [i915#3886]) +2 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_ccs@pipe-a-bad-pixel-format-y_tiled_gen12_mc_ccs.html

  * igt@kms_ccs@pipe-a-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][48] ([i915#3689] / [i915#6095])
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_ccs@pipe-a-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs.html

  * igt@kms_ccs@pipe-b-random-ccs-data-yf_tiled_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][49] ([fdo#111615] / [i915#3689]) +3 similar issues
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_ccs@pipe-b-random-ccs-data-yf_tiled_ccs.html

  * igt@kms_ccs@pipe-c-bad-rotation-90-y_tiled_gen12_mc_ccs:
    - shard-apl:          NOTRUN -> [SKIP][50] ([fdo#109271] / [i915#3886])
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl2/igt@kms_ccs@pipe-c-bad-rotation-90-y_tiled_gen12_mc_ccs.html
    - shard-iclb:         NOTRUN -> [SKIP][51] ([fdo#109278] / [i915#3886])
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@kms_ccs@pipe-c-bad-rotation-90-y_tiled_gen12_mc_ccs.html

  * igt@kms_ccs@pipe-d-bad-pixel-format-4_tiled_dg2_rc_ccs_cc:
    - shard-tglb:         NOTRUN -> [SKIP][52] ([i915#3689]) +3 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@kms_ccs@pipe-d-bad-pixel-format-4_tiled_dg2_rc_ccs_cc.html

  * igt@kms_ccs@pipe-d-random-ccs-data-4_tiled_dg2_rc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][53] ([i915#6095])
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb8/igt@kms_ccs@pipe-d-random-ccs-data-4_tiled_dg2_rc_ccs.html

  * {igt@kms_chamelium_color@ctm-green-to-red} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][54] ([fdo#109284]) +10 similar issues
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@kms_chamelium_color@ctm-green-to-red.html

  * {igt@kms_chamelium_color@ctm-negative} (NEW):
    - shard-glk:          NOTRUN -> [SKIP][55] ([fdo#109271]) +85 similar issues
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk7/igt@kms_chamelium_color@ctm-negative.html

  * {igt@kms_chamelium_color@gamma} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][56] ([fdo#109284]) +10 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb3/igt@kms_chamelium_color@gamma.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-storm} (NEW):
    - shard-apl:          NOTRUN -> [SKIP][57] ([fdo#109271]) +84 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl2/igt@kms_chamelium_hpd@hdmi-hpd-storm.html

  * igt@kms_content_protection@dp-mst-lic-type-0:
    - shard-tglb:         NOTRUN -> [SKIP][58] ([i915#3116] / [i915#3299])
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb3/igt@kms_content_protection@dp-mst-lic-type-0.html
    - shard-iclb:         NOTRUN -> [SKIP][59] ([i915#3116])
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@kms_content_protection@dp-mst-lic-type-0.html

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy:
    - shard-glk:          [PASS][60] -> [FAIL][61] ([i915#72])
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk1/igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy.html
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk2/igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy.html

  * igt@kms_cursor_legacy@flip-vs-cursor@atomic-transitions-varying-size:
    - shard-glk:          [PASS][62] -> [FAIL][63] ([i915#2346])
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk7/igt@kms_cursor_legacy@flip-vs-cursor@atomic-transitions-varying-size.html
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk3/igt@kms_cursor_legacy@flip-vs-cursor@atomic-transitions-varying-size.html

  * igt@kms_dither@fb-8bpc-vs-panel-8bpc:
    - shard-tglb:         NOTRUN -> [SKIP][64] ([i915#1769] / [i915#3555])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_dither@fb-8bpc-vs-panel-8bpc.html

  * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@bc-hdmi-a1-hdmi-a2:
    - shard-glk:          [PASS][65] -> [FAIL][66] ([i915#79])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk8/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@bc-hdmi-a1-hdmi-a2.html
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk2/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@bc-hdmi-a1-hdmi-a2.html

  * igt@kms_flip@2x-modeset-vs-vblank-race-interruptible:
    - shard-iclb:         NOTRUN -> [SKIP][67] ([fdo#109274]) +1 similar issue
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb8/igt@kms_flip@2x-modeset-vs-vblank-race-interruptible.html

  * igt@kms_flip@2x-nonexisting-fb-interruptible:
    - shard-tglb:         NOTRUN -> [SKIP][68] ([fdo#109274] / [fdo#111825] / [i915#3637]) +4 similar issues
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@kms_flip@2x-nonexisting-fb-interruptible.html

  * igt@kms_flip@flip-vs-dpms-off-vs-modeset@a-hdmi-a1:
    - shard-glk:          [PASS][69] -> [DMESG-WARN][70] ([i915#118])
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk3/igt@kms_flip@flip-vs-dpms-off-vs-modeset@a-hdmi-a1.html
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk4/igt@kms_flip@flip-vs-dpms-off-vs-modeset@a-hdmi-a1.html

  * igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-downscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][71] ([i915#2672]) +2 similar issues
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-downscaling@pipe-a-default-mode.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling@pipe-a-valid-mode:
    - shard-iclb:         NOTRUN -> [SKIP][72] ([i915#2587] / [i915#2672]) +3 similar issues
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb5/igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling@pipe-a-valid-mode:
    - shard-tglb:         NOTRUN -> [SKIP][73] ([i915#2587] / [i915#2672])
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling@pipe-a-valid-mode:
    - shard-iclb:         NOTRUN -> [SKIP][74] ([i915#2672] / [i915#3555])
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb5/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling@pipe-a-valid-mode.html

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt:
    - shard-glk:          [PASS][75] -> [FAIL][76] ([i915#2546])
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt.html
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk4/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt.html

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-plflip-blt:
    - shard-tglb:         NOTRUN -> [SKIP][77] ([fdo#109280] / [fdo#111825]) +17 similar issues
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb5/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-plflip-blt.html

  * igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu:
    - shard-iclb:         NOTRUN -> [SKIP][78] ([fdo#109280]) +8 similar issues
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb6/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-wc:
    - shard-tglb:         NOTRUN -> [SKIP][79] ([i915#6497]) +4 similar issues
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-cpu:
    - shard-snb:          NOTRUN -> [SKIP][80] ([fdo#109271]) +114 similar issues
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-snb7/igt@kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-cpu.html

  * igt@kms_plane_scaling@2x-scaler-multi-pipe:
    - shard-tglb:         NOTRUN -> [SKIP][81] ([fdo#109274] / [fdo#111825])
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@kms_plane_scaling@2x-scaler-multi-pipe.html

  * igt@kms_plane_scaling@planes-unity-scaling-downscale-factor-0-25@pipe-c-edp-1:
    - shard-tglb:         NOTRUN -> [SKIP][82] ([i915#5235]) +3 similar issues
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@kms_plane_scaling@planes-unity-scaling-downscale-factor-0-25@pipe-c-edp-1.html

  * igt@kms_psr2_sf@cursor-plane-move-continuous-exceed-sf:
    - shard-tglb:         NOTRUN -> [SKIP][83] ([i915#2920])
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb6/igt@kms_psr2_sf@cursor-plane-move-continuous-exceed-sf.html

  * igt@kms_psr2_su@page_flip-p010@pipe-b-edp-1:
    - shard-iclb:         NOTRUN -> [FAIL][84] ([i915#5939]) +2 similar issues
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb2/igt@kms_psr2_su@page_flip-p010@pipe-b-edp-1.html

  * igt@kms_psr2_su@page_flip-xrgb8888:
    - shard-iclb:         NOTRUN -> [SKIP][85] ([fdo#109642] / [fdo#111068] / [i915#658])
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb1/igt@kms_psr2_su@page_flip-xrgb8888.html

  * igt@kms_psr@psr2_cursor_blt:
    - shard-iclb:         NOTRUN -> [SKIP][86] ([fdo#109441])
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb7/igt@kms_psr@psr2_cursor_blt.html

  * igt@kms_psr@psr2_cursor_mmap_cpu:
    - shard-tglb:         NOTRUN -> [FAIL][87] ([i915#132] / [i915#3467]) +2 similar issues
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb8/igt@kms_psr@psr2_cursor_mmap_cpu.html

  * igt@kms_psr@psr2_sprite_mmap_cpu:
    - shard-iclb:         [PASS][88] -> [SKIP][89] ([fdo#109441])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb2/igt@kms_psr@psr2_sprite_mmap_cpu.html
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb8/igt@kms_psr@psr2_sprite_mmap_cpu.html

  * igt@kms_setmode@invalid-clone-single-crtc-stealing:
    - shard-tglb:         NOTRUN -> [SKIP][90] ([i915#3555]) +3 similar issues
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@kms_setmode@invalid-clone-single-crtc-stealing.html
    - shard-iclb:         NOTRUN -> [SKIP][91] ([i915#3555])
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb6/igt@kms_setmode@invalid-clone-single-crtc-stealing.html

  * igt@kms_vblank@pipe-d-wait-busy-hang:
    - shard-iclb:         NOTRUN -> [SKIP][92] ([fdo#109278]) +4 similar issues
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb2/igt@kms_vblank@pipe-d-wait-busy-hang.html

  * igt@prime_vgem@fence-flip-hang:
    - shard-tglb:         NOTRUN -> [SKIP][93] ([fdo#109295])
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@prime_vgem@fence-flip-hang.html

  * igt@sysfs_clients@sema-25:
    - shard-apl:          NOTRUN -> [SKIP][94] ([fdo#109271] / [i915#2994])
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl6/igt@sysfs_clients@sema-25.html
    - shard-tglb:         NOTRUN -> [SKIP][95] ([i915#2994])
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb5/igt@sysfs_clients@sema-25.html
    - shard-iclb:         NOTRUN -> [SKIP][96] ([i915#2994])
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@sysfs_clients@sema-25.html

  
#### Possible fixes ####

  * igt@gem_exec_fair@basic-flow@rcs0:
    - shard-tglb:         [FAIL][97] ([i915#2842]) -> [PASS][98]
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb2/igt@gem_exec_fair@basic-flow@rcs0.html
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb1/igt@gem_exec_fair@basic-flow@rcs0.html

  * igt@gem_huc_copy@huc-copy:
    - shard-tglb:         [SKIP][99] ([i915#2190]) -> [PASS][100]
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb7/igt@gem_huc_copy@huc-copy.html
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb2/igt@gem_huc_copy@huc-copy.html

  * igt@kms_cursor_legacy@flip-vs-cursor@toggle:
    - shard-iclb:         [FAIL][101] ([i915#2346]) -> [PASS][102] +1 similar issue
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb7/igt@kms_cursor_legacy@flip-vs-cursor@toggle.html
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb6/igt@kms_cursor_legacy@flip-vs-cursor@toggle.html

  * igt@kms_flip@flip-vs-expired-vblank-interruptible@c-dp1:
    - shard-apl:          [FAIL][103] ([i915#79]) -> [PASS][104]
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-apl7/igt@kms_flip@flip-vs-expired-vblank-interruptible@c-dp1.html
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl2/igt@kms_flip@flip-vs-expired-vblank-interruptible@c-dp1.html

  * igt@kms_flip@flip-vs-expired-vblank@b-hdmi-a2:
    - shard-glk:          [FAIL][105] ([i915#79]) -> [PASS][106]
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk9/igt@kms_flip@flip-vs-expired-vblank@b-hdmi-a2.html
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk3/igt@kms_flip@flip-vs-expired-vblank@b-hdmi-a2.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling@pipe-a-valid-mode:
    - shard-tglb:         [INCOMPLETE][107] -> [PASS][108]
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb8/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling@pipe-a-valid-mode.html
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb5/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling@pipe-a-default-mode:
    - shard-iclb:         [SKIP][109] ([i915#3555]) -> [PASS][110]
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb2/igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling@pipe-a-default-mode.html
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling@pipe-a-default-mode.html

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-cpu:
    - shard-glk:          [FAIL][111] ([i915#2546]) -> [PASS][112]
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk6/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-cpu.html
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk6/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-cpu.html

  * igt@kms_plane_cursor@viewport@pipe-a-hdmi-a-1-size-64:
    - shard-glk:          [FAIL][113] -> [PASS][114]
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk1/igt@kms_plane_cursor@viewport@pipe-a-hdmi-a-1-size-64.html
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk3/igt@kms_plane_cursor@viewport@pipe-a-hdmi-a-1-size-64.html

  * igt@kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats@pipe-b-edp-1:
    - shard-iclb:         [SKIP][115] ([i915#5176]) -> [PASS][116] +1 similar issue
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb3/igt@kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats@pipe-b-edp-1.html
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb6/igt@kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats@pipe-b-edp-1.html

  * igt@kms_psr@psr2_cursor_plane_move:
    - shard-iclb:         [SKIP][117] ([fdo#109441]) -> [PASS][118] +1 similar issue
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb7/igt@kms_psr@psr2_cursor_plane_move.html
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb2/igt@kms_psr@psr2_cursor_plane_move.html

  * igt@kms_psr_stress_test@invalidate-primary-flip-overlay:
    - shard-iclb:         [SKIP][119] ([i915#5519]) -> [PASS][120]
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb7/igt@kms_psr_stress_test@invalidate-primary-flip-overlay.html
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb3/igt@kms_psr_stress_test@invalidate-primary-flip-overlay.html

  
#### Warnings ####

  * igt@gem_pread@exhaustion:
    - shard-tglb:         [WARN][121] ([i915#2658]) -> [INCOMPLETE][122] ([i915#7248])
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb1/igt@gem_pread@exhaustion.html
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb7/igt@gem_pread@exhaustion.html

  * igt@gem_pwrite@basic-exhaustion:
    - shard-tglb:         [INCOMPLETE][123] ([i915#7248]) -> [WARN][124] ([i915#2658])
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-tglb6/igt@gem_pwrite@basic-exhaustion.html
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-tglb3/igt@gem_pwrite@basic-exhaustion.html
    - shard-glk:          [INCOMPLETE][125] ([i915#7248]) -> [WARN][126] ([i915#2658])
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-glk4/igt@gem_pwrite@basic-exhaustion.html
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-glk5/igt@gem_pwrite@basic-exhaustion.html

  * igt@i915_pm_dc@dc3co-vpb-simulation:
    - shard-iclb:         [SKIP][127] ([i915#658]) -> [SKIP][128] ([i915#588])
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb3/igt@i915_pm_dc@dc3co-vpb-simulation.html
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb2/igt@i915_pm_dc@dc3co-vpb-simulation.html

  * igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area:
    - shard-iclb:         [SKIP][129] ([i915#2920]) -> [SKIP][130] ([fdo#111068] / [i915#658])
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-iclb2/igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area.html
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-iclb5/igt@kms_psr2_sf@overlay-primary-update-sf-dmg-area.html

  * igt@runner@aborted:
    - shard-apl:          ([FAIL][131], [FAIL][132]) ([i915#3002] / [i915#4312]) -> ([FAIL][133], [FAIL][134], [FAIL][135]) ([fdo#109271] / [i915#3002] / [i915#4312])
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-apl7/igt@runner@aborted.html
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12460/shard-apl8/igt@runner@aborted.html
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl3/igt@runner@aborted.html
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl8/igt@runner@aborted.html
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/shard-apl1/igt@runner@aborted.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109279]: https://bugs.freedesktop.org/show_bug.cgi?id=109279
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109283]: https://bugs.freedesktop.org/show_bug.cgi?id=109283
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109291]: https://bugs.freedesktop.org/show_bug.cgi?id=109291
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [fdo#109302]: https://bugs.freedesktop.org/show_bug.cgi?id=109302
  [fdo#109303]: https://bugs.freedesktop.org/show_bug.cgi?id=109303
  [fdo#109307]: https://bugs.freedesktop.org/show_bug.cgi?id=109307
  [fdo#109308]: https://bugs.freedesktop.org/show_bug.cgi?id=109308
  [fdo#109309]: https://bugs.freedesktop.org/show_bug.cgi?id=109309
  [fdo#109312]: https://bugs.freedesktop.org/show_bug.cgi?id=109312
  [fdo#109314]: https://bugs.freedesktop.org/show_bug.cgi?id=109314
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109506]: https://bugs.freedesktop.org/show_bug.cgi?id=109506
  [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
  [fdo#110723]: https://bugs.freedesktop.org/show_bug.cgi?id=110723
  [fdo#110892]: https://bugs.freedesktop.org/show_bug.cgi?id=110892
  [fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068
  [fdo#111614]: https://bugs.freedesktop.org/show_bug.cgi?id=111614
  [fdo#111615]: https://bugs.freedesktop.org/show_bug.cgi?id=111615
  [fdo#111644]: https://bugs.freedesktop.org/show_bug.cgi?id=111644
  [fdo#111656]: https://bugs.freedesktop.org/show_bug.cgi?id=111656
  [fdo#111825]: https://bugs.freedesktop.org/show_bug.cgi?id=111825
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [fdo#112054]: https://bugs.freedesktop.org/show_bug.cgi?id=112054
  [fdo#112283]: https://bugs.freedesktop.org/show_bug.cgi?id=112283
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118
  [i915#1257]: https://gitlab.freedesktop.org/drm/intel/issues/1257
  [i915#132]: https://gitlab.freedesktop.org/drm/intel/issues/132
  [i915#1397]: https://gitlab.freedesktop.org/drm/intel/issues/1397
  [i915#1769]: https://gitlab.freedesktop.org/drm/intel/issues/1769
  [i915#1825]: https://gitlab.freedesktop.org/drm/intel/issues/1825
  [i915#1839]: https://gitlab.freedesktop.org/drm/intel/issues/1839
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
  [i915#1850]: https://gitlab.freedesktop.org/drm/intel/issues/1850
  [i915#1902]: https://gitlab.freedesktop.org/drm/intel/issues/1902
  [i915#1937]: https://gitlab.freedesktop.org/drm/intel/issues/1937
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2346]: https://gitlab.freedesktop.org/drm/intel/issues/2346
  [i915#2410]: https://gitlab.freedesktop.org/drm/intel/issues/2410
  [i915#2411]: https://gitlab.freedesktop.org/drm/intel/issues/2411
  [i915#2433]: https://gitlab.freedesktop.org/drm/intel/issues/2433
  [i915#2434]: https://gitlab.freedesktop.org/drm/intel/issues/2434
  [i915#2435]: https://gitlab.freedesktop.org/drm/intel/issues/2435
  [i915#2437]: https://gitlab.freedesktop.org/drm/intel/issues/2437
  [i915#2527]: https://gitlab.freedesktop.org/drm/intel/issues/2527
  [i915#2532]: https://gitlab.freedesktop.org/drm/intel/issues/2532
  [i915#2546]: https://gitlab.freedesktop.org/drm/intel/issues/2546
  [i915#2575]: https://gitlab.freedesktop.org/drm/intel/issues/2575
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2587]: https://gitlab.freedesktop.org/drm/intel/issues/2587
  [i915#2658]: https://gitlab.freedesktop.org/drm/intel/issues/2658
  [i915#2672]: https://gitlab.freedesktop.org/drm/intel/issues/2672
  [i915#2681]: https://gitlab.freedesktop.org/drm/intel/issues/2681
  [i915#2705]: https://gitlab.freedesktop.org/drm/intel/issues/2705
  [i915#280]: https://gitlab.freedesktop.org/drm/intel/issues/280
  [i915#284]: https://gitlab.freedesktop.org/drm/intel/issues/284
  [i915#2842]: https://gitlab.freedesktop.org/drm/intel/issues/2842
  [i915#2856]: https://gitlab.freedesktop.org/drm/intel/issues/2856
  [i915#2920]: https://gitlab.freedesktop.org/drm/intel/issues/2920
  [i915#2994]: https://gitlab.freedesktop.org/drm/intel/issues/2994
  [i915#3002]: https://gitlab.freedesktop.org/drm/intel/issues/3002
  [i915#3116]: https://gitlab.freedesktop.org/drm/intel/issues/3116
  [i915#3281]: https://gitlab.freedesktop.org/drm/intel/issues/3281
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3297]: https://gitlab.freedesktop.org/drm/intel/issues/3297
  [i915#3299]: https://gitlab.freedesktop.org/drm/intel/issues/3299
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3318]: https://gitlab.freedesktop.org/drm/intel/issues/3318
  [i915#3323]: https://gitlab.freedesktop.org/drm/intel/issues/3323
  [i915#3359]: https://gitlab.freedesktop.org/drm/intel/issues/3359
  [i915#3361]: https://gitlab.freedesktop.org/drm/intel/issues/3361
  [i915#3458]: https://gitlab.freedesktop.org/drm/intel/issues/3458
  [i915#3467]: https://gitlab.freedesktop.org/drm/intel/issues/3467
  [i915#3469]: https://gitlab.freedesktop.org/drm/intel/issues/3469
  [i915#3528]: https://gitlab.freedesktop.org/drm/intel/issues/3528
  [i915#3536]: https://gitlab.freedesktop.org/drm/intel/issues/3536
  [i915#3539]: https://gitlab.freedesktop.org/drm/intel/issues/3539
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3558]: https://gitlab.freedesktop.org/drm/intel/issues/3558
  [i915#3637]: https://gitlab.freedesktop.org/drm/intel/issues/3637
  [i915#3638]: https://gitlab.freedesktop.org/drm/intel/issues/3638
  [i915#3689]: https://gitlab.freedesktop.org/drm/intel/issues/3689
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#3734]: https://gitlab.freedesktop.org/drm/intel/issues/3734
  [i915#3742]: https://gitlab.freedesktop.org/drm/intel/issues/3742
  [i915#3778]: https://gitlab.freedesktop.org/drm/intel/issues/3778
  [i915#3804]: https://gitlab.freedesktop.org/drm/intel/issues/3804
  [i915#3826]: https://gitlab.freedesktop.org/drm/intel/issues/3826
  [i915#3840]: https://gitlab.freedesktop.org/drm/intel/issues/3840
  [i915#3886]: https://gitlab.freedesktop.org/drm/intel/issues/3886
  [i915#3952]: https://gitlab.freedesktop.org/drm/intel/issues/3952
  [i915#3955]: https://gitlab.freedesktop.org/drm/intel/issues/3955
  [i915#3966]: https://gitlab.freedesktop.org/drm/intel/issues/3966
  [i915#3989]: https://gitlab.freedesktop.org/drm/intel/issues/3989
  [i915#4036]: https://gitlab.freedesktop.org/drm/intel/issues/4036
  [i915#404]: https://gitlab.freedesktop.org/drm/intel/issues/404
  [i915#4070]: https://gitlab.freedesktop.org/drm/intel/issues/4070
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4098]: https://gitlab.freedesktop.org/drm/intel/issues/4098
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4171]: https://gitlab.freedesktop.org/drm/intel/issues/4171
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#426]: https://gitlab.freedesktop.org/drm/intel/issues/426
  [i915#4270]: https://gitlab.freedesktop.org/drm/intel/issues/4270
  [i915#4281]: https://gitlab.freedesktop.org/drm/intel/issues/4281
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#433]: https://gitlab.freedesktop.org/drm/intel/issues/433
  [i915#4349]: https://gitlab.freedesktop.org/drm/intel/issues/4349
  [i915#4387]: https://gitlab.freedesktop.org/drm/intel/issues/4387
  [i915#4525]: https://gitlab.freedesktop.org/drm/intel/issues/4525
  [i915#4538]: https://gitlab.freedesktop.org/drm/intel/issues/4538
  [i915#454]: https://gitlab.freedesktop.org/drm/intel/issues/454
  [i915#4565]: https://gitlab.freedesktop.org/drm/intel/issues/4565
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4767]: https://gitlab.freedesktop.org/drm/intel/issues/4767
  [i915#4771]: https://gitlab.freedesktop.org/drm/intel/issues/4771
  [i915#4812]: https://gitlab.freedesktop.org/drm/intel/issues/4812
  [i915#4818]: https://gitlab.freedesktop.org/drm/intel/issues/4818
  [i915#4833]: https://gitlab.freedesktop.org/drm/intel/issues/4833
  [i915#4852]: https://gitlab.freedesktop.org/drm/intel/issues/4852
  [i915#4854]: https://gitlab.freedesktop.org/drm/intel/issues/4854
  [i915#4855]: https://gitlab.freedesktop.org/drm/intel/issues/4855
  [i915#4859]: https://gitlab.freedesktop.org/drm/intel/issues/4859
  [i915#4860]: https://gitlab.freedesktop.org/drm/intel/issues/4860
  [i915#4877]: https://gitlab.freedesktop.org/drm/intel/issues/4877
  [i915#4880]: https://gitlab.freedesktop.org/drm/intel/issues/4880
  [i915#4884]: https://gitlab.freedesktop.org/drm/intel/issues/4884
  [i915#4885]: https://gitlab.freedesktop.org/drm/intel/issues/4885
  [i915#4991]: https://gitlab.freedesktop.org/drm/intel/issues/4991
  [i915#5176]: https://gitlab.freedesktop.org/drm/intel/issues/5176
  [i915#5235]: https://gitlab.freedesktop.org/drm/intel/issues/5235
  [i915#5286]: https://gitlab.freedesktop.org/drm/intel/issues/5286
  [i915#5288]: https://gitlab.freedesktop.org/drm/intel/issues/5288
  [i915#5289]: https://gitlab.freedesktop.org/drm/intel/issues/5289
  [i915#5325]: https://gitlab.freedesktop.org/drm/intel/issues/5325
  [i915#5327]: https://gitlab.freedesktop.org/drm/intel/issues/5327
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#5439]: https://gitlab.freedesktop.org/drm/intel/issues/5439
  [i915#5461]: https://gitlab.freedesktop.org/drm/intel/issues/5461
  [i915#5519]: https://gitlab.freedesktop.org/drm/intel/issues/5519
  [i915#5563]: https://gitlab.freedesktop.org/drm/intel/issues/5563
  [i915#5566]: https://gitlab.freedesktop.org/drm/intel/issues/5566
  [i915#588]: https://gitlab.freedesktop.org/drm/intel/issues/588
  [i915#5939]: https://gitlab.freedesktop.org/drm/intel/issues/5939
  [i915#6095]: https://gitlab.freedesktop.org/drm/intel/issues/6095
  [i915#6227]: https://gitlab.freedesktop.org/drm/intel/issues/6227
  [i915#6230]: https://gitlab.freedesktop.org/drm/intel/issues/6230
  [i915#6245]: https://gitlab.freedesktop.org/drm/intel/issues/6245
  [i915#6248]: https://gitlab.freedesktop.org/drm/intel/issues/6248
  [i915#6268]: https://gitlab.freedesktop.org/drm/intel/issues/6268
  [i915#6301]: https://gitlab.freedesktop.org/drm/intel/issues/6301
  [i915#6334]: https://gitlab.freedesktop.org/drm/intel/issues/6334
  [i915#6335]: https://gitlab.freedesktop.org/drm/intel/issues/6335
  [i915#6412]: https://gitlab.freedesktop.org/drm/intel/issues/6412
  [i915#6433]: https://gitlab.freedesktop.org/drm/intel/issues/6433
  [i915#6463]: https://gitlab.freedesktop.org/drm/intel/issues/6463
  [i915#6493]: https://gitlab.freedesktop.org/drm/intel/issues/6493
  [i915#6497]: https://gitlab.freedesktop.org/drm/intel/issues/6497
  [i915#6524]: https://gitlab.freedesktop.org/drm/intel/issues/6524
  [i915#658]: https://gitlab.freedesktop.org/drm/intel/issues/658
  [i915#6590]: https://gitlab.freedesktop.org/drm/intel/issues/6590
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6768]: https://gitlab.freedesktop.org/drm/intel/issues/6768
  [i915#6944]: https://gitlab.freedesktop.org/drm/intel/issues/6944
  [i915#6946]: https://gitlab.freedesktop.org/drm/intel/issues/6946
  [i915#7116]: https://gitlab.freedesktop.org/drm/intel/issues/7116
  [i915#7118]: https://gitlab.freedesktop.org/drm/intel/issues/7118
  [i915#716]: https://gitlab.freedesktop.org/drm/intel/issues/716
  [i915#7178]: https://gitlab.freedesktop.org/drm/intel/issues/7178
  [i915#72]: https://gitlab.freedesktop.org/drm/intel/issues/72
  [i915#7248]: https://gitlab.freedesktop.org/drm/intel/issues/7248
  [i915#7276]: https://gitlab.freedesktop.org/drm/intel/issues/7276
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
  [i915#7582]: https://gitlab.freedesktop.org/drm/intel/issues/7582
  [i915#768]: https://gitlab.freedesktop.org/drm/intel/issues/768
  [i915#79]: https://gitlab.freedesktop.org/drm/intel/issues/79


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7078 -> IGTPW_8182
  * Piglit: piglit_4509 -> None

  CI-20190529: 20190529
  CI_DRM_12460: 0b96883d5e7a2baa9f75d50656e722c61d96c08f @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8182: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html
  IGT_7078: 71bce31c26998d5d53cff3138049261fd6c4fbaf @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8182/index.html

[-- Attachment #2: Type: text/html, Size: 50764 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] [PATCH v2] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-12-01 16:29 ` [igt-dev] [PATCH v2] " Mark Yacoub
@ 2022-12-02  9:48   ` Petri Latvala
  2022-12-06 18:56   ` [igt-dev] [PATCH v3] " Mark Yacoub
  1 sibling, 0 replies; 25+ messages in thread
From: Petri Latvala @ 2022-12-02  9:48 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: robdclark, vsuley, amstan, ihf, igt-dev, kalin, seanpaul,
	matthewtlam, markyacoub, khaled.almahallawy

On Thu, Dec 01, 2022 at 11:29:31AM -0500, Mark Yacoub wrote:
> [Why]
> kms_chamelium tests file has grown so much and became a bit big to
> manage.
> Splitting specific tests like we do for kms_ tests into separate files
> puts logically related functionalities into the same place so tests are
> more clear.
> 
> [How]
> Split kms_chamelium into 4 different tests, each testing something
> specific. The tests are:
> 1. kms_chamelium_audio
> 2. kms_chamelium_edid
> 3. kms_chamelium_frames
> 4. kms_chamelium_hpd
> 5. kms_chamelium_color which used to be kms_color_chamelium but renamed
>    for consistency.
> 
> All common code lives in kms_chamelium_helper and the function names
> have a chamelium_ prefix.
> 
> v1:
> Fix typo and add missing #include
> 
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> ---
>  docs/chamelium.txt                            |    2 +-
>  lib/igt_edid.h                                |    1 +
>  lib/igt_eld.h                                 |    1 +
>  lib/monitor_edids/monitor_edids_helper.c      |    2 +-
>  tests/chamelium/kms_chamelium.c               | 3132 -----------------
>  tests/chamelium/kms_chamelium_audio.c         |  858 +++++
>  ...olor_chamelium.c => kms_chamelium_color.c} |    0
>  tests/chamelium/kms_chamelium_edid.c          |  534 +++
>  tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
>  tests/chamelium/kms_chamelium_helper.c        |  330 ++
>  tests/chamelium/kms_chamelium_helper.h        |   74 +
>  tests/chamelium/kms_chamelium_hpd.c           |  512 +++
>  tests/intel-ci/blacklist.txt                  |    2 +-
>  tests/intel-ci/fast-feedback.testlist         |   18 +-
>  tests/kms_color_helper.h                      |    2 +-
>  tests/meson.build                             |   14 +-
>  tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
>  17 files changed, 3431 insertions(+), 3164 deletions(-)
>  delete mode 100644 tests/chamelium/kms_chamelium.c
>  create mode 100644 tests/chamelium/kms_chamelium_audio.c
>  rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
>  create mode 100644 tests/chamelium/kms_chamelium_edid.c
>  create mode 100644 tests/chamelium/kms_chamelium_frames.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.h
>  create mode 100644 tests/chamelium/kms_chamelium_hpd.c
> 
> diff --git a/docs/chamelium.txt b/docs/chamelium.txt
> index c4c22468..f82c8b0c 100644
> --- a/docs/chamelium.txt
> +++ b/docs/chamelium.txt
> @@ -241,7 +241,7 @@ Current Support in IGT
>  
>  Support for the Chamelium platform in IGT is found in the following places:
>  * lib/igt_chamelium.c: library with Chamelium-related helpers
> -* tests/kms_chamelium.c: sub-tests using the Chamelium
> +* tests/kms_chamelium_*.c: sub-tests using the Chamelium
>  
>  As of early April 2019, the following features are tested by IGT:
>  * Pixel-by-pixel frame integrity tests for DP and HDMI
> diff --git a/lib/igt_edid.h b/lib/igt_edid.h
> index 477f16c2..85a9ef5e 100644
> --- a/lib/igt_edid.h
> +++ b/lib/igt_edid.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdint.h>
> +#include <stddef.h>
>  
>  #include <xf86drmMode.h>
>  
> diff --git a/lib/igt_eld.h b/lib/igt_eld.h
> index 30d7012d..1a46b6d2 100644
> --- a/lib/igt_eld.h
> +++ b/lib/igt_eld.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdbool.h>
> +#include <stddef.h>
>  
>  #include "igt_edid.h"
>  
> diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
> index 41f199bd..1cbf1c22 100644
> --- a/lib/monitor_edids/monitor_edids_helper.c
> +++ b/lib/monitor_edids/monitor_edids_helper.c
> @@ -1,4 +1,4 @@
> -// SPDX-License-Identifier: GPL-2.0
> +// SPDX-License-Identifier: MIT
>  /*
>   * A helper library for parsing and making use of real EDID data from monitors
>   * and make them compatible with IGT and Chamelium.
> diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
> deleted file mode 100644
> index 3c4b4d75..00000000
> --- a/tests/chamelium/kms_chamelium.c
> +++ /dev/null
> @@ -1,3132 +0,0 @@
> -/*
> - * Copyright © 2016 Red Hat Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - * Authors:
> - *    Lyude Paul <lyude@redhat.com>
> - */
> -
> -#include "config.h"
> -#include "igt.h"
> -#include "igt_vc4.h"
> -#include "igt_edid.h"
> -#include "igt_eld.h"
> -#include "igt_infoframe.h"
> -#include "monitor_edids/dp_edids.h"
> -#include "monitor_edids/hdmi_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,
> -	TEST_MODESET_ON_OFF,
> -	TEST_MODESET_OFF,
> -};
> -
> -typedef struct {
> -	struct chamelium *chamelium;
> -	struct chamelium_port **ports;
> -	igt_display_t display;
> -	int port_count;
> -
> -	int drm_fd;
> -
> -	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> -} data_t;
> -
> -#define ONLINE_TIMEOUT 20 /* seconds */
> -
> -#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> -#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> -
> -#define HPD_TOGGLE_COUNT_VGA 5
> -#define HPD_TOGGLE_COUNT_DP_HDMI 15
> -#define HPD_TOGGLE_COUNT_FAST 3
> -
> -static void
> -get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
> -{
> -	drmModeConnector *connector;
> -	uint64_t link_status;
> -	drmModePropertyPtr prop;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		connector = chamelium_port_get_connector(data->chamelium,
> -							 data->ports[p], false);
> -
> -		igt_assert(kmstest_get_property(data->drm_fd,
> -						connector->connector_id,
> -						DRM_MODE_OBJECT_CONNECTOR,
> -						"link-status", NULL,
> -						&link_status, &prop));
> -
> -		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> -
> -		drmModeFreeProperty(prop);
> -		drmModeFreeConnector(connector);
> -	}
> -}
> -
> -/* Wait for hotplug and return the remaining time left from timeout */
> -static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> -{
> -	struct timespec start, end;
> -	int elapsed;
> -	bool detected;
> -
> -	igt_assert_eq(igt_gettime(&start), 0);
> -	detected = igt_hotplug_detected(mon, *timeout);
> -	igt_assert_eq(igt_gettime(&end), 0);
> -
> -	elapsed = igt_time_elapsed(&start, &end);
> -	igt_assert_lte(0, elapsed);
> -	*timeout = max(0, *timeout - elapsed);
> -
> -	return detected;
> -}
> -
> -static void
> -wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
> -				 struct chamelium_port *port,
> -				 drmModeConnection status)
> -{
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int hotplug_count = 0;
> -
> -	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> -			  chamelium_port_get_name(port),
> -			  kmstest_connector_status_str(status));
> -
> -	while (timeout > 0) {
> -		if (!wait_for_hotplug(mon, &timeout))
> -			break;
> -
> -		hotplug_count++;
> -
> -		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> -						port) == status)
> -			return;
> -	}
> -
> -	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> -			    chamelium_port_get_name(port),
> -			    kmstest_connector_status_str(status),
> -			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
> -}
> -
> -
> -static int chamelium_vga_modes[][2] = {
> -	{ 1600, 1200 },
> -	{ 1920, 1200 },
> -	{ 1920, 1080 },
> -	{ 1680, 1050 },
> -	{ 1280, 1024 },
> -	{ 1280, 960 },
> -	{ 1440, 900 },
> -	{ 1280, 800 },
> -	{ 1024, 768 },
> -	{ 1360, 768 },
> -	{ 1280, 720 },
> -	{ 800, 600 },
> -	{ 640, 480 },
> -	{ -1, -1 },
> -};
> -
> -static bool
> -prune_vga_mode(data_t *data, drmModeModeInfo *mode)
> -{
> -	int i = 0;
> -
> -	while (chamelium_vga_modes[i][0] != -1) {
> -		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> -		    mode->vdisplay == chamelium_vga_modes[i][1])
> -			return false;
> -
> -		i++;
> -	}
> -
> -	return true;
> -}
> -
> -static bool
> -check_analog_bridge(data_t *data, struct chamelium_port *port)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -	uint64_t edid_blob_id;
> -	const struct edid *edid;
> -	char edid_vendor[3];
> -
> -	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> -		drmModeFreeConnector(connector);
> -		return false;
> -	}
> -
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	edid = (const struct edid *) edid_blob->data;
> -	edid_get_mfg(edid, edid_vendor);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -
> -	/* Analog bridges provide their own EDID */
> -	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> -	    edid_vendor[2] != 'T')
> -		return true;
> -
> -	return false;
> -}
> -
> -static void chamelium_paint_xr24_pattern(uint32_t *data,
> -					 size_t width, size_t height,
> -					 size_t stride, size_t block_size)
> -{
> -	uint32_t colors[] = { 0xff000000,
> -			      0xffff0000,
> -			      0xff00ff00,
> -			      0xff0000ff,
> -			      0xffffffff };
> -	unsigned i, j;
> -
> -	for (i = 0; i < height; i++)
> -		for (j = 0; j < width; j++)
> -			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
> -}
> -
> -static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
> -				    uint32_t fourcc, size_t block_size,
> -				    struct igt_fb *fb)
> -{
> -	int fb_id;
> -	void *ptr;
> -
> -	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> -
> -	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> -			      DRM_FORMAT_MOD_LINEAR, fb);
> -	igt_assert(fb_id > 0);
> -
> -	ptr = igt_fb_map_buffer(fb->fd, fb);
> -	igt_assert(ptr);
> -
> -	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> -				     block_size);
> -	igt_fb_unmap_buffer(fb, ptr);
> -
> -	return fb_id;
> -}
> -
> -static void
> -enable_output(data_t *data,
> -	      struct chamelium_port *port,
> -	      igt_output_t *output,
> -	      drmModeModeInfo *mode,
> -	      struct igt_fb *fb)
> -{
> -	igt_display_t *display = output->display;
> -	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -
> -	igt_assert(primary);
> -
> -	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> -	igt_plane_set_fb(primary, fb);
> -	igt_output_override_mode(output, mode);
> -
> -	/* Clear any color correction values that might be enabled */
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
> -
> -	igt_display_commit2(display, COMMIT_ATOMIC);
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> -		usleep(250000);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
> -{
> -	enum pipe pipe;
> -
> -	for_each_pipe(display, pipe) {
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			return pipe;
> -		}
> -	}
> -
> -	igt_assert_f(false, "No pipe found for output %s\n",
> -		     igt_output_name(output));
> -}
> -
> -static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
> -{
> -	int fb_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, fb);
> -
> -	igt_assert(fb_id > 0);
> -}
> -
> -static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
> -								   port, false);
> -	drmModeModeInfo mode;
> -	igt_assert(&connector->modes[0] != NULL);
> -	memcpy(&mode, &connector->modes[0], sizeof(mode));
> -	drmModeFreeConnector(connector);
> -	return mode;
> -}
> -
> -static igt_output_t *get_output_for_port(data_t *data,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector =
> -		chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_output_t *output = igt_output_from_connector(&data->display,
> -							 connector);
> -	drmModeFreeConnector(connector);
> -	igt_assert(output != NULL);
> -	return output;
> -}
> -
> -static const char test_hotplug_for_each_pipe_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug for each pipe with valid output";
> -static void
> -test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	enum pipe pipe;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	chamelium_reset_state(&data->display,
> -			      data->chamelium,
> -			      port,
> -			      data->ports,
> -			      data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	/* Disconnect if any port got connected */
> -	chamelium_unplug(data->chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port,
> -			DRM_MODE_DISCONNECTED);
> -
> -	for_each_pipe(&data->display, pipe) {
> -		igt_flush_uevents(mon);
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -		output = get_output_for_port(data, port);
> -
> -		/* If pipe is valid for output then set it */
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			igt_output_set_pipe(output, pipe);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -
> -		chamelium_unplug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_DISCONNECTED);
> -		igt_flush_uevents(mon);
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_basic_hotplug_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug";
> -static void
> -test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
> -	     enum test_modeset_mode modeset_mode)
> -{
> -	int i;
> -	enum pipe pipe;
> -	struct igt_fb fb = {0};
> -	drmModeModeInfo mode;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	igt_output_t *output = get_output_for_port(data, port);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -
> -	for (i = 0; i < toggle_count; i++) {
> -		igt_flush_uevents(mon);
> -
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF ||
> -		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
> -			if (i == 0) {
> -				/* We can only get mode and pipe once we are connected */
> -				output = get_output_for_port(data, port);
> -				pipe = get_pipe_for_output(&data->display, output);
> -				mode = get_mode_for_port(data->chamelium, port);
> -				create_fb_for_mode(data, &fb, &mode);
> -			}
> -
> -			igt_output_set_pipe(output, pipe);
> -			enable_output(data, port, output, &mode, &fb);
> -		}
> -
> -		/* Now check if we get a hotplug from disconnection */
> -		chamelium_unplug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_DISCONNECTED);
> -
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF) {
> -			igt_output_set_pipe(output, PIPE_NONE);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static void set_edid(data_t *data, struct chamelium_port *port,
> -		     enum igt_custom_edid_type edid)
> -{
> -	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> -}
> -
> -static const char igt_custom_edid_type_read_desc[] =
> -	"Make sure the EDID exposed by KMS is the same as the screen's";
> -static void
> -igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector;
> -	size_t raw_edid_size;
> -	const struct edid *raw_edid;
> -	uint64_t edid_blob_id;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_skip_on(check_analog_bridge(data, port));
> -
> -	connector = chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob_id != 0);
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> -	raw_edid_size = edid_get_size(raw_edid);
> -	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void
> -try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -		       enum igt_suspend_state state, enum igt_suspend_test test,
> -		       struct udev_monitor *mon, bool connected)
> -{
> -	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> -						     DRM_MODE_CONNECTED;
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int delay;
> -	int p;
> -
> -	igt_flush_uevents(mon);
> -
> -	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> -
> -	if (port) {
> -		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> -					      !connected);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			port = data->ports[p];
> -			chamelium_schedule_hpd_toggle(data->chamelium, port,
> -						      delay, !connected);
> -		}
> -
> -		port = NULL;
> -	}
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(wait_for_hotplug(mon, &timeout));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	if (port) {
> -		igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -							  data->chamelium,
> -							  port),
> -							  target_state);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			drmModeConnection current_state;
> -
> -			port = data->ports[p];
> -			/*
> -			 * There could be as many hotplug events sent by
> -			 * driver as connectors we scheduled an HPD toggle on
> -			 * above, depending on timing. So if we're not seeing
> -			 * the expected connector state try to wait for an HPD
> -			 * event for each connector/port.
> -			 */
> -			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			if (p > 0 && current_state != target_state) {
> -				igt_assert(wait_for_hotplug(mon, &timeout));
> -				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			}
> -
> -			igt_assert_eq(current_state, target_state);
> -		}
> -
> -		port = NULL;
> -	}
> -}
> -
> -static const char test_suspend_resume_hpd_desc[] =
> -	"Toggle HPD during suspend, check that uevents are sent and connector "
> -	"status is updated";
> -static void
> -test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -			enum igt_suspend_state state,
> -			enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_hpd_common_desc[] =
> -	"Toggle HPD during suspend on all connectors, check that uevents are "
> -	"sent and connector status is updated";
> -static void
> -test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
> -			       enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	struct chamelium_port *port;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		port = data->ports[p];
> -		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_edid_change_desc[] =
> -	"Simulate a screen being unplugged and another screen being plugged "
> -	"during suspend, check that a uevent is sent and connector status is "
> -	"updated";
> -static void
> -test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
> -				enum igt_suspend_state state,
> -				enum igt_suspend_test test,
> -				enum igt_custom_edid_type edid,
> -				enum igt_custom_edid_type alt_edid)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	bool link_status_failed[2][data->port_count];
> -	int p;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Catch the event and flush all remaining ones. */
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_flush_uevents(mon);
> -
> -	/* First plug in the port */
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	/*
> -	 * Change the edid before we suspend. On resume, the machine should
> -	 * notice the EDID change and fire a hotplug event.
> -	 */
> -	set_edid(data, port, alt_edid);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[0]);
> -
> -	igt_flush_uevents(mon);
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[1]);
> -
> -	for (p = 0; p < data->port_count; p++)
> -		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
> -}
> -
> -static igt_output_t *
> -prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	igt_display_t *display = &data->display;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	/* The chamelium's default EDID has a lot of resolutions, way more then
> -	 * we need to test. Additionally the default EDID doesn't support HDMI
> -	 * audio.
> -	 */
> -	set_edid(data, port, edid);
> -
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_display_reset(display);
> -
> -	output = get_output_for_port(data, port);
> -
> -	/* Refresh pipe to update connected status */
> -	igt_output_set_pipe(output, PIPE_NONE);
> -
> -	pipe = get_pipe_for_output(display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	return output;
> -}
> -
> -static void do_test_display(data_t *data, struct chamelium_port *port,
> -			    igt_output_t *output, drmModeModeInfo *mode,
> -			    uint32_t fourcc, enum chamelium_check check,
> -			    int count)
> -{
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	struct igt_fb frame_fb, fb;
> -	int i, fb_id, captured_frame_count;
> -	int frame_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
> -				  DRM_FORMAT_MOD_LINEAR);
> -	igt_assert(frame_id > 0);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&fb);
> -
> -	enable_output(data, port, output, mode, &frame_fb);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		igt_crc_t *expected_crc;
> -		igt_crc_t *crc;
> -
> -		/* We want to keep the display running for a little bit, since
> -		 * there's always the potential the driver isn't able to keep
> -		 * the display running properly for very long
> -		 */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == count);
> -
> -		igt_debug("Captured %d frames\n", captured_frame_count);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		for (i = 0; i < captured_frame_count; i++)
> -			chamelium_assert_crc_eq_or_dump(data->chamelium,
> -							expected_crc, &crc[i],
> -							&fb, i);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> -		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		igt_assert(count == 1);
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG)
> -			chamelium_crop_analog_frame(dump, mode->hdisplay,
> -						    mode->vdisplay);
> -
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	igt_remove_fb(data->drm_fd, &frame_fb);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static const char test_display_one_mode_desc[] =
> -	"Pick the first mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_one_mode(data_t *data, struct chamelium_port *port,
> -				  uint32_t fourcc, enum chamelium_check check,
> -				  int count)
> -{
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
> -
> -	mode = &connector->modes[0];
> -	if (check == CHAMELIUM_CHECK_ANALOG) {
> -		bool bridge = check_analog_bridge(data, port);
> -
> -		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> -	}
> -
> -	do_test_display(data, port, output, mode, fourcc, check, count);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static const char test_display_all_modes_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_all_modes(data_t *data, struct chamelium_port *port,
> -				   uint32_t fourcc, enum chamelium_check check,
> -				   int count)
> -{
> -	bool bridge;
> -	int i, count_modes;
> -
> -	if (check == CHAMELIUM_CHECK_ANALOG)
> -		bridge = check_analog_bridge(data, port);
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -		igt_require(igt_plane_has_format_mod(primary, fourcc,
> -			    DRM_FORMAT_MOD_LINEAR));
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> -		    prune_vga_mode(data, mode))
> -			continue;
> -
> -		do_test_display(data, port, output, mode, fourcc, check,
> -				count);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -static const char test_display_frame_dump_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then download the captured frames and compare them "
> -	"bit-by-bit to the sent ones";
> -static void
> -test_display_frame_dump(data_t *data, struct chamelium_port *port)
> -{
> -
> -	int i, count_modes;
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		struct igt_fb fb;
> -		struct chamelium_frame_dump *frame;
> -		drmModeModeInfo *mode;
> -		drmModeConnector *connector;
> -		int fb_id, j;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		igt_debug("Reading frame dumps from Chamelium...\n");
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> -		for (j = 0; j < 5; j++) {
> -			frame = chamelium_read_captured_frame(data->chamelium,
> -							      j);
> -			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> -			chamelium_destroy_frame_dump(frame);
> -		}
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> -
> -static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> -		       drmModeModeInfo *mode)
> -{
> -	struct chamelium_video_params video_params = {0};
> -	double mode_clock;
> -	int mode_hsync_offset, mode_vsync_offset;
> -	int mode_hsync_width, mode_vsync_width;
> -	int mode_hsync_polarity, mode_vsync_polarity;
> -
> -	chamelium_port_get_video_params(chamelium, port, &video_params);
> -
> -	mode_clock = (double) mode->clock / 1000;
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> -		/* this is what chamelium understands as offsets for DP */
> -		mode_hsync_offset = mode->htotal - mode->hsync_start;
> -		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> -	} else {
> -		/* and this is what they are for other connectors */
> -		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> -		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> -	}
> -
> -	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> -	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> -
> -	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> -	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> -
> -	igt_debug("Checking video mode:\n");
> -	igt_debug("clock: got %f, expected %f ± %f%%\n",
> -		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
> -	igt_debug("hactive: got %d, expected %d\n",
> -		  video_params.hactive, mode->hdisplay);
> -	igt_debug("vactive: got %d, expected %d\n",
> -		  video_params.vactive, mode->vdisplay);
> -	igt_debug("hsync_offset: got %d, expected %d\n",
> -		  video_params.hsync_offset, mode_hsync_offset);
> -	igt_debug("vsync_offset: got %d, expected %d\n",
> -		  video_params.vsync_offset, mode_vsync_offset);
> -	igt_debug("htotal: got %d, expected %d\n",
> -		  video_params.htotal, mode->htotal);
> -	igt_debug("vtotal: got %d, expected %d\n",
> -		  video_params.vtotal, mode->vtotal);
> -	igt_debug("hsync_width: got %d, expected %d\n",
> -		  video_params.hsync_width, mode_hsync_width);
> -	igt_debug("vsync_width: got %d, expected %d\n",
> -		  video_params.vsync_width, mode_vsync_width);
> -	igt_debug("hsync_polarity: got %d, expected %d\n",
> -		  video_params.hsync_polarity, mode_hsync_polarity);
> -	igt_debug("vsync_polarity: got %d, expected %d\n",
> -		  video_params.vsync_polarity, mode_vsync_polarity);
> -
> -	if (!isnan(video_params.clock)) {
> -		igt_assert(video_params.clock >
> -			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> -		igt_assert(video_params.clock <
> -			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> -	}
> -	igt_assert(video_params.hactive == mode->hdisplay);
> -	igt_assert(video_params.vactive == mode->vdisplay);
> -	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> -	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> -	igt_assert(video_params.htotal == mode->htotal);
> -	igt_assert(video_params.vtotal == mode->vtotal);
> -	igt_assert(video_params.hsync_width == mode_hsync_width);
> -	igt_assert(video_params.vsync_width == mode_vsync_width);
> -	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> -	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> -}
> -
> -static const char test_mode_timings_desc[] =
> -	"For each mode of the IGT base EDID, perform a modeset and check the "
> -	"mode detected by the Chamelium receiver matches the mode we set";
> -static void test_mode_timings(data_t *data, struct chamelium_port *port)
> -{
> -	int i, count_modes;
> -
> -	i = 0;
> -	igt_require(chamelium_supports_get_video_params(data->chamelium));
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -		int fb_id;
> -		struct igt_fb fb;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port, false);
> -		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		/* Trigger the FSM */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> -
> -		check_mode(data->chamelium, port, mode);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -struct vic_mode {
> -	int hactive, vactive;
> -	int vrefresh; /* Hz */
> -	uint32_t picture_ar;
> -};
> -
> -/* Maps Video Identification Codes to a mode */
> -static const struct vic_mode vic_modes[] = {
> -	[16] = {
> -		.hactive = 1920,
> -		.vactive = 1080,
> -		.vrefresh = 60,
> -		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> -	},
> -};
> -
> -/* Maps aspect ratios to their mode flag */
> -static const uint32_t mode_ar_flags[] = {
> -	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> -};
> -
> -static enum infoframe_avi_picture_aspect_ratio
> -get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> -{
> -	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> -	switch (aspect_ratio) {
> -	case DRM_MODE_PICTURE_ASPECT_4_3:
> -		return INFOFRAME_AVI_PIC_AR_4_3;
> -	case DRM_MODE_PICTURE_ASPECT_16_9:
> -		return INFOFRAME_AVI_PIC_AR_16_9;
> -	default:
> -		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> -	}
> -}
> -
> -static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> -				 drmModeModeInfo *drm_mode)
> -{
> -	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> -
> -	return vic_mode->hactive == drm_mode->hdisplay &&
> -	       vic_mode->vactive == drm_mode->vdisplay &&
> -	       vic_mode->vrefresh == drm_mode->vrefresh &&
> -	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> -}
> -
> -static const char test_display_aspect_ratio_desc[] =
> -	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> -	"check they include the relevant fields";
> -static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	int fb_id, i;
> -	struct igt_fb fb;
> -	bool found, ok;
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_avi infoframe_avi;
> -	uint8_t vic = 16; /* TODO: test more VICs */
> -	const struct vic_mode *vic_mode;
> -	uint32_t aspect_ratio;
> -	enum infoframe_avi_picture_aspect_ratio frame_ar;
> -
> -	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	vic_mode = &vic_modes[vic];
> -	aspect_ratio = vic_mode->picture_ar;
> -
> -	found = false;
> -	igt_assert(connector->count_modes > 0);
> -	for (i = 0; i < connector->count_modes; i++) {
> -		mode = &connector->modes[i];
> -
> -		if (vic_mode_matches_drm(vic_mode, mode)) {
> -			found = true;
> -			break;
> -		}
> -	}
> -	igt_assert_f(found,
> -		     "Failed to find mode with the correct aspect ratio\n");
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> -						 CHAMELIUM_INFOFRAME_AVI);
> -	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> -
> -	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> -				 infoframe->payload, infoframe->payload_size);
> -	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> -
> -	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> -
> -	igt_debug("Checking AVI InfoFrame\n");
> -	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> -		  infoframe_avi.picture_aspect_ratio, frame_ar);
> -	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> -		  infoframe_avi.vic, vic);
> -
> -	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> -	igt_assert(infoframe_avi.vic == vic);
> -
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_remove_fb(data->drm_fd, &fb);
> -	drmModeFreeConnector(connector);
> -}
> -
> -
> -/* Playback parameters control the audio signal we synthesize and send */
> -#define PLAYBACK_CHANNELS 2
> -#define PLAYBACK_SAMPLES 1024
> -
> -/* Capture paremeters control the audio signal we receive */
> -#define CAPTURE_SAMPLES 2048
> -
> -#define AUDIO_TIMEOUT 2000 /* ms */
> -/* A streak of 3 gives confidence that the signal is good. */
> -#define MIN_STREAK 3
> -
> -#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> -#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> -#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> -
> -/* TODO: enable >48KHz rates, these are not reliable */
> -static int test_sampling_rates[] = {
> -	32000,
> -	44100,
> -	48000,
> -	/* 88200, */
> -	/* 96000, */
> -	/* 176400, */
> -	/* 192000, */
> -};
> -
> -static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
> -
> -/* Test frequencies (Hz): a sine signal will be generated for each.
> - *
> - * Depending on the sampling rate chosen, it might not be possible to properly
> - * detect the generated sine (see Nyquist–Shannon sampling theorem).
> - * Frequencies that can't be reliably detected will be automatically pruned in
> - * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> - * tested with a 192KHz sampling rate.
> - */
> -static int test_frequencies[] = {
> -	300,
> -	600,
> -	1200,
> -	10000,
> -	80000,
> -};
> -
> -static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> -
> -static const snd_pcm_format_t test_formats[] = {
> -	SND_PCM_FORMAT_S16_LE,
> -	SND_PCM_FORMAT_S24_LE,
> -	SND_PCM_FORMAT_S32_LE,
> -};
> -
> -static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
> -
> -struct audio_state {
> -	struct alsa *alsa;
> -	struct chamelium *chamelium;
> -	struct chamelium_port *port;
> -	struct chamelium_stream *stream;
> -
> -	/* The capture format is only available after capture has started. */
> -	struct {
> -		snd_pcm_format_t format;
> -		int channels;
> -		int rate;
> -	} playback, capture;
> -
> -	char *name;
> -	struct audio_signal *signal; /* for frequencies test only */
> -	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	size_t recv_pages;
> -	int msec;
> -
> -	int dump_fd;
> -	char *dump_path;
> -
> -	pthread_t thread;
> -	atomic_bool run;
> -	atomic_bool positive; /* for pulse test only */
> -};
> -
> -static void audio_state_init(struct audio_state *state, data_t *data,
> -			     struct alsa *alsa, struct chamelium_port *port,
> -			     snd_pcm_format_t format, int channels, int rate)
> -{
> -	memset(state, 0, sizeof(*state));
> -	state->dump_fd = -1;
> -
> -	state->alsa = alsa;
> -	state->chamelium = data->chamelium;
> -	state->port = port;
> -
> -	state->playback.format = format;
> -	state->playback.channels = channels;
> -	state->playback.rate = rate;
> -
> -	alsa_configure_output(alsa, format, channels, rate);
> -
> -	state->stream = chamelium_stream_init();
> -	igt_assert_f(state->stream,
> -		     "Failed to initialize Chamelium stream client\n");
> -}
> -
> -static void audio_state_fini(struct audio_state *state)
> -{
> -	chamelium_stream_deinit(state->stream);
> -	free(state->name);
> -}
> -
> -static void *run_audio_thread(void *data)
> -{
> -	struct alsa *alsa = data;
> -
> -	alsa_run(alsa, -1);
> -	return NULL;
> -}
> -
> -static void audio_state_start(struct audio_state *state, const char *name)
> -{
> -	int ret;
> -	bool ok;
> -	size_t i, j;
> -	enum chamelium_stream_realtime_mode stream_mode;
> -	char dump_suffix[64];
> -
> -	free(state->name);
> -	state->name = strdup(name);
> -	state->recv_pages = 0;
> -	state->msec = 0;
> -
> -	igt_debug("Starting %s test with playback format %s, "
> -		  "sampling rate %d Hz and %d channels\n",
> -		  name, snd_pcm_format_name(state->playback.format),
> -		  state->playback.rate, state->playback.channels);
> -
> -	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> -
> -	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> -	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> -	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> -
> -	/* Start playing audio */
> -	state->run = true;
> -	ret = pthread_create(&state->thread, NULL,
> -			     run_audio_thread, state->alsa);
> -	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> -
> -	/* The Chamelium device only supports this PCM format. */
> -	state->capture.format = SND_PCM_FORMAT_S32_LE;
> -
> -	/* Only after we've started playing audio, we can retrieve the capture
> -	 * format used by the Chamelium device. */
> -	chamelium_get_audio_format(state->chamelium, state->port,
> -				   &state->capture.rate,
> -				   &state->capture.channels);
> -	if (state->capture.rate == 0) {
> -		igt_debug("Audio receiver doesn't indicate the capture "
> -			 "sampling rate, assuming it's %d Hz\n",
> -			 state->playback.rate);
> -		state->capture.rate = state->playback.rate;
> -	}
> -
> -	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> -					    state->channel_mapping);
> -	/* Make sure we can capture all channels we send. */
> -	for (i = 0; i < state->playback.channels; i++) {
> -		ok = false;
> -		for (j = 0; j < state->capture.channels; j++) {
> -			if (state->channel_mapping[j] == i) {
> -				ok = true;
> -				break;
> -			}
> -		}
> -		igt_assert_f(ok, "Cannot capture all channels\n");
> -	}
> -
> -	if (igt_frame_dump_is_enabled()) {
> -		snprintf(dump_suffix, sizeof(dump_suffix),
> -			 "capture-%s-%s-%dch-%dHz",
> -			 name, snd_pcm_format_name(state->playback.format),
> -			 state->playback.channels, state->playback.rate);
> -
> -		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> -							      state->capture.rate,
> -							      state->capture.channels,
> -							      &state->dump_path);
> -		igt_assert_f(state->dump_fd >= 0,
> -			     "Failed to create audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_receive(struct audio_state *state,
> -				int32_t **recv, size_t *recv_len)
> -{
> -	bool ok;
> -	size_t page_count;
> -	size_t recv_size;
> -
> -	ok = chamelium_stream_receive_realtime_audio(state->stream,
> -						     &page_count,
> -						     recv, recv_len);
> -	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> -
> -	state->msec = state->recv_pages * *recv_len
> -		      / (double) state->capture.channels
> -		      / (double) state->capture.rate * 1000;
> -	state->recv_pages++;
> -
> -	if (state->dump_fd >= 0) {
> -		recv_size = *recv_len * sizeof(int32_t);
> -		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
> -			     "Failed to write to audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_stop(struct audio_state *state, bool success)
> -{
> -	bool ok;
> -	int ret;
> -	struct chamelium_audio_file *audio_file;
> -	enum igt_log_level log_level;
> -
> -	igt_debug("Stopping audio playback\n");
> -	state->run = false;
> -	ret = pthread_join(state->thread, NULL);
> -	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> -
> -	ok = chamelium_stream_stop_realtime_audio(state->stream);
> -	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> -
> -	audio_file = chamelium_stop_capturing_audio(state->chamelium,
> -						    state->port);
> -	if (audio_file) {
> -		igt_debug("Audio file saved on the Chamelium in %s\n",
> -			  audio_file->path);
> -		chamelium_destroy_audio_file(audio_file);
> -	}
> -
> -	if (state->dump_fd >= 0) {
> -		close(state->dump_fd);
> -		state->dump_fd = -1;
> -
> -		if (success) {
> -			/* Test succeeded, no need to keep the captured data */
> -			unlink(state->dump_path);
> -		} else
> -			igt_debug("Saved captured audio data to %s\n",
> -				  state->dump_path);
> -		free(state->dump_path);
> -		state->dump_path = NULL;
> -	}
> -
> -	if (success)
> -		log_level = IGT_LOG_DEBUG;
> -	else
> -		log_level = IGT_LOG_CRITICAL;
> -
> -	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
> -		"sampling rate %d Hz and %d channels: %s\n",
> -		state->name, snd_pcm_format_name(state->playback.format),
> -		state->playback.rate, state->playback.channels,
> -		success ? "ALL GREEN" : "FAILED");
> -
> -}
> -
> -static void check_audio_infoframe(struct audio_state *state)
> -{
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_audio infoframe_audio;
> -	struct infoframe_audio expected = {0};
> -	bool ok;
> -
> -	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "Chamelium board doesn't support GetLastInfoFrame\n");
> -		return;
> -	}
> -
> -	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> -	expected.channel_count = state->playback.channels;
> -	expected.sampling_freq = state->playback.rate;
> -	expected.sample_size = snd_pcm_format_width(state->playback.format);
> -
> -	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> -						 CHAMELIUM_INFOFRAME_AUDIO);
> -	if (infoframe == NULL && state->playback.channels <= 2) {
> -		/* Audio InfoFrames are optional for mono and stereo audio */
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "no InfoFrame received\n");
> -		return;
> -	}
> -	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> -
> -	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> -				   infoframe->payload, infoframe->payload_size);
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> -
> -	igt_debug("Checking audio InfoFrame:\n");
> -	igt_debug("coding_type: got %d, expected %d\n",
> -		  infoframe_audio.coding_type, expected.coding_type);
> -	igt_debug("channel_count: got %d, expected %d\n",
> -		  infoframe_audio.channel_count, expected.channel_count);
> -	igt_debug("sampling_freq: got %d, expected %d\n",
> -		  infoframe_audio.sampling_freq, expected.sampling_freq);
> -	igt_debug("sample_size: got %d, expected %d\n",
> -		  infoframe_audio.sample_size, expected.sample_size);
> -
> -	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> -		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> -	if (infoframe_audio.channel_count >= 0)
> -		igt_assert(infoframe_audio.channel_count == expected.channel_count);
> -	if (infoframe_audio.sampling_freq >= 0)
> -		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
> -	if (infoframe_audio.sample_size >= 0)
> -		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> -}
> -
> -static int
> -audio_output_frequencies_callback(void *data, void *buffer, int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	audio_signal_fill(state->signal, tmp, samples);
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool test_audio_frequencies(struct audio_state *state)
> -{
> -	int freq, step;
> -	int32_t *recv, *buf;
> -	double *channel;
> -	size_t i, j, streak;
> -	size_t recv_len, buf_len, buf_cap, channel_len;
> -	bool success;
> -	int capture_chan;
> -
> -	state->signal = audio_signal_init(state->playback.channels,
> -					  state->playback.rate);
> -	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> -
> -	/* We'll choose different frequencies per channel to make sure they are
> -	 * independent from each other. To do so, we'll add a different offset
> -	 * to the base frequencies for each channel. We need to choose a big
> -	 * enough offset so that we're sure to detect mixed up channels. We
> -	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> -	 * difference.
> -	 *
> -	 * Note that we assume capture_rate == playback_rate. We'll assert this
> -	 * later on. We cannot retrieve the capture rate before starting
> -	 * playing audio, so we don't really have the choice.
> -	 */
> -	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> -	for (i = 0; i < test_frequencies_count; i++) {
> -		for (j = 0; j < state->playback.channels; j++) {
> -			freq = test_frequencies[i] + j * step;
> -			audio_signal_add_frequency(state->signal, freq, j);
> -		}
> -	}
> -	audio_signal_synthesize(state->signal);
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_frequencies_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	audio_state_start(state, "frequencies");
> -
> -	igt_assert_f(state->capture.rate == state->playback.rate,
> -		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> -		     state->capture.rate, state->playback.rate);
> -
> -	/* Needs to be a multiple of 128, because that's the number of samples
> -	 * we get per channel each time we receive an audio page from the
> -	 * Chamelium device.
> -	 *
> -	 * Additionally, this value needs to be high enough to guarantee we
> -	 * capture a full period of each sine we generate. If we capture 2048
> -	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> -	 * sines. For lower sampling rates, the capture duration will be
> -	 * longer.
> -	 */
> -	channel_len = CAPTURE_SAMPLES;
> -	channel = malloc(sizeof(double) * channel_len);
> -
> -	buf_cap = state->capture.channels * channel_len;
> -	buf = malloc(sizeof(int32_t) * buf_cap);
> -	buf_len = 0;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -
> -	success = false;
> -	streak = 0;
> -	while (!success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> -		buf_len += recv_len;
> -
> -		if (buf_len < buf_cap)
> -			continue;
> -		igt_assert(buf_len == buf_cap);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (j = 0; j < state->playback.channels; j++) {
> -			capture_chan = state->channel_mapping[j];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", j, capture_chan);
> -
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     buf, buf_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			if (audio_signal_detect(state->signal,
> -						state->capture.rate, j,
> -						channel, channel_len))
> -				streak++;
> -			else
> -				streak = 0;
> -		}
> -
> -		buf_len = 0;
> -
> -		success = streak == MIN_STREAK * state->playback.channels;
> -	}
> -
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -	free(buf);
> -	free(channel);
> -	audio_signal_fini(state->signal);
> -
> -	check_audio_infoframe(state);
> -
> -	return success;
> -}
> -
> -static int audio_output_flatline_callback(void *data, void *buffer,
> -					     int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len, i;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	for (i = 0; i < len; i++)
> -		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> -{
> -	double expected, min, max;
> -	size_t i;
> -	bool ok;
> -
> -	min = max = NAN;
> -	for (i = 0; i < buf_len; i++) {
> -		if (isnan(min) || buf[i] < min)
> -			min = buf[i];
> -		if (isnan(max) || buf[i] > max)
> -			max = buf[i];
> -	}
> -
> -	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> -	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> -	if (ok)
> -		igt_debug("Flatline wave amplitude detected\n");
> -	else
> -		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> -			  min, max);
> -	return ok;
> -}
> -
> -static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> -{
> -	size_t i;
> -
> -	for (i = 0; i < buf_len; i++) {
> -		if (buf[i] < 0)
> -			return i;
> -	}
> -
> -	return -1;
> -}
> -
> -/** test_audio_flatline:
> - *
> - * Send a constant value (one positive, then a negative one) and check that:
> - *
> - * - The amplitude of the flatline is correct
> - * - All channels switch from a positive signal to a negative one at the same
> - *   time (ie. all channels are aligned)
> - */
> -static bool test_audio_flatline(struct audio_state *state)
> -{
> -	bool success, amp_success, align_success;
> -	int32_t *recv;
> -	size_t recv_len, i, channel_len;
> -	ssize_t j;
> -	int streak, capture_chan;
> -	double *channel;
> -	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_flatline_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	/* Start by sending a positive signal */
> -	state->positive = true;
> -
> -	audio_state_start(state, "flatline");
> -
> -	for (i = 0; i < state->playback.channels; i++)
> -		falling_edges[i] = -1;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -	amp_success = false;
> -	streak = 0;
> -	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (i = 0; i < state->playback.channels; i++) {
> -			capture_chan = state->channel_mapping[i];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", i, capture_chan);
> -
> -			channel_len = audio_extract_channel_s32_le(NULL, 0,
> -								   recv, recv_len,
> -								   state->capture.channels,
> -								   capture_chan);
> -			channel = malloc(channel_len * sizeof(double));
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     recv, recv_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			/* Check whether the amplitude is fine */
> -			if (detect_flatline_amplitude(channel, channel_len,
> -						      state->positive))
> -				streak++;
> -			else
> -				streak = 0;
> -
> -			/* If we're now sending a negative signal, detect the
> -			 * falling edge */
> -			j = detect_falling_edge(channel, channel_len);
> -			if (!state->positive && j >= 0) {
> -				falling_edges[i] = recv_len * state->recv_pages
> -						   + j;
> -			}
> -
> -			free(channel);
> -		}
> -
> -		amp_success = streak == MIN_STREAK * state->playback.channels;
> -
> -		if (amp_success && state->positive) {
> -			/* Switch to a negative signal after we've detected the
> -			 * positive one. */
> -			state->positive = false;
> -			amp_success = false;
> -			streak = 0;
> -			igt_debug("Switching to negative square wave\n");
> -		}
> -	}
> -
> -	/* Check alignment between all channels by comparing the index of the
> -	 * falling edge. */
> -	align_success = true;
> -	for (i = 0; i < state->playback.channels; i++) {
> -		if (falling_edges[i] < 0) {
> -			igt_critical("Falling edge not detected for channel %zu\n",
> -				     i);
> -			align_success = false;
> -			continue;
> -		}
> -
> -		if (abs(falling_edges[0] - falling_edges[i]) >
> -		    FLATLINE_ALIGN_ACCURACY) {
> -			igt_critical("Channel alignment mismatch: "
> -				     "channel 0 has a falling edge at index %d "
> -				     "while channel %zu has index %d\n",
> -				     falling_edges[0], i, falling_edges[i]);
> -			align_success = false;
> -		}
> -	}
> -
> -	success = amp_success && align_success;
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -
> -	return success;
> -}
> -
> -static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
> -				      int channels, int sampling_rate)
> -{
> -	if (!alsa_test_output_configuration(alsa, format, channels,
> -					    sampling_rate)) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because at least one of the "
> -			  "selected output devices doesn't support this "
> -			  "configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	/* TODO: the Chamelium device sends a malformed signal for some audio
> -	 * configurations. See crbug.com/950917 */
> -	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> -			channels > 2) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because the Chamelium device "
> -			  "doesn't support this configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	return true;
> -}
> -
> -static const char test_display_audio_desc[] =
> -	"Playback various audio signals with various audio formats/rates, "
> -	"capture them and check they are correct";
> -static void
> -test_display_audio(data_t *data, struct chamelium_port *port,
> -		   const char *audio_device, enum igt_custom_edid_type edid)
> -{
> -	bool run, success;
> -	struct alsa *alsa;
> -	int ret;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id, i, j;
> -	int channels, sampling_rate;
> -	snd_pcm_format_t format;
> -	struct audio_state state;
> -
> -	igt_require(alsa_has_exclusive_access());
> -
> -	/* Old Chamelium devices need an update for DisplayPort audio and
> -	 * chamelium_get_audio_format support. */
> -	igt_require(chamelium_has_audio_support(data->chamelium, port));
> -
> -	alsa = alsa_init();
> -	igt_assert(alsa);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because the receiver won't try to receive audio if
> -	 * it doesn't receive video. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	run = false;
> -	success = true;
> -	for (i = 0; i < test_sampling_rates_count; i++) {
> -		for (j = 0; j < test_formats_count; j++) {
> -			ret = alsa_open_output(alsa, audio_device);
> -			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> -
> -			/* TODO: playback on all 8 available channels (this
> -			 * isn't supported by Chamelium devices yet, see
> -			 * https://crbug.com/950917) */
> -			format = test_formats[j];
> -			channels = PLAYBACK_CHANNELS;
> -			sampling_rate = test_sampling_rates[i];
> -
> -			if (!check_audio_configuration(alsa, format, channels,
> -						       sampling_rate))
> -				continue;
> -
> -			run = true;
> -
> -			audio_state_init(&state, data, alsa, port,
> -					 format, channels, sampling_rate);
> -			success &= test_audio_frequencies(&state);
> -			success &= test_audio_flatline(&state);
> -			audio_state_fini(&state);
> -
> -			alsa_close_output(alsa);
> -		}
> -	}
> -
> -	/* Make sure we tested at least one frequency and format. */
> -	igt_assert(run);
> -	/* Make sure all runs were successful. */
> -	igt_assert(success);
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -
> -	free(alsa);
> -}
> -
> -static const char test_display_audio_edid_desc[] =
> -	"Plug a connector with an EDID suitable for audio, check ALSA's "
> -	"EDID-Like Data reports the correct audio parameters";
> -static void
> -test_display_audio_edid(data_t *data, struct chamelium_port *port,
> -			enum igt_custom_edid_type edid)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id;
> -	struct eld_entry eld;
> -	struct eld_sad *sad;
> -
> -	igt_require(eld_is_supported());
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because audio cannot be played on inactive
> -	 * connectors. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	igt_assert(eld_get_igt(&eld));
> -	igt_assert(eld.sads_len == 1);
> -
> -	sad = &eld.sads[0];
> -	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> -	igt_assert(sad->channels == 2);
> -	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
> -		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
> -	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
> -		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void randomize_plane_stride(data_t *data,
> -				   uint32_t width, uint32_t height,
> -				   uint32_t format, uint64_t modifier,
> -				   size_t *stride)
> -{
> -	size_t stride_min;
> -	uint32_t max_tile_w = 4, tile_w, tile_h;
> -	int i;
> -	struct igt_fb dummy;
> -
> -	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> -
> -	/* Randomize the stride to less than twice the minimum. */
> -	*stride = (rand() % stride_min) + stride_min;
> -
> -	/*
> -	 * Create a dummy FB to determine bpp for each plane, and calculate
> -	 * the maximum tile width from that.
> -	 */
> -	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> -	for (i = 0; i < dummy.num_planes; i++) {
> -		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
> -
> -		if (tile_w > max_tile_w)
> -			max_tile_w = tile_w;
> -	}
> -	igt_remove_fb(data->drm_fd, &dummy);
> -
> -	/*
> -	 * Pixman requires the stride to be aligned to 32-bits, which is
> -	 * reflected in the initial value of max_tile_w and the hw
> -	 * may require a multiple of tile width, choose biggest of the 2.
> -	 */
> -	*stride = ALIGN(*stride, max_tile_w);
> -}
> -
> -static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> -				  uint32_t height, uint32_t format,
> -				  uint64_t *modifier)
> -{
> -	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> -		/* Randomize the column height to less than twice the minimum. */
> -		size_t column_height = (rand() % height) + height;
> -
> -		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
> -			  column_height);
> -
> -		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
> -	}
> -}
> -
> -static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
> -				  drmModeModeInfo *mode,
> -				  uint32_t *width, uint32_t *height,
> -				  uint32_t *format, uint64_t *modifier,
> -				  bool allow_yuv)
> -{
> -	int min_dim;
> -	uint32_t idx[plane->format_mod_count];
> -	unsigned int count = 0;
> -	unsigned int i;
> -
> -	/* First pass to count the supported formats. */
> -	for (i = 0; i < plane->format_mod_count; i++)
> -		if (igt_fb_supported_format(plane->formats[i]) &&
> -		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> -			idx[count++] = i;
> -
> -	igt_assert(count > 0);
> -
> -	i = idx[rand() % count];
> -	*format = plane->formats[i];
> -	*modifier = plane->modifiers[i];
> -
> -	update_tiled_modifier(plane, *width, *height, *format, modifier);
> -
> -	/*
> -	 * Randomize width and height in the mode dimensions range.
> -	 *
> -	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> -	 * least min_dim, because src_w = width - (rand % w / 2).
> -	 *
> -	 * Use a minimum dimension of 16 for YUV, because planar YUV
> -	 * subsamples the UV plane.
> -	 */
> -	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> -
> -	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> -	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> -}
> -
> -static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> -			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> -			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> -			    struct igt_fb *fb)
> -{
> -	igt_plane_set_fb(plane, fb);
> -
> -	igt_plane_set_position(plane, crtc_x, crtc_y);
> -	igt_plane_set_size(plane, crtc_w, crtc_h);
> -
> -	igt_fb_set_position(fb, plane, src_x, src_y);
> -	igt_fb_set_size(fb, plane, src_w, src_h);
> -}
> -
> -static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
> -					drmModeModeInfo *mode,
> -					struct igt_fb *fb,
> -					uint32_t *src_w, uint32_t *src_h,
> -					uint32_t *src_x, uint32_t *src_y,
> -					uint32_t *crtc_w, uint32_t *crtc_h,
> -					int32_t *crtc_x, int32_t *crtc_y,
> -					bool allow_scaling)
> -{
> -	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> -	uint32_t width = fb->width, height = fb->height;
> -	double ratio;
> -	int ret;
> -
> -	/* Randomize source offset in the first half of the original size. */
> -	*src_x = rand() % (width / 2);
> -	*src_y = rand() % (height / 2);
> -
> -	/* The source size only includes the active source area. */
> -	*src_w = width - *src_x;
> -	*src_h = height - *src_y;
> -
> -	if (allow_scaling) {
> -		*crtc_w = (rand() % mode->hdisplay) + 1;
> -		*crtc_h = (rand() % mode->vdisplay) + 1;
> -
> -		/*
> -		 * Don't bother with scaling if dimensions are quite close in
> -		 * order to get non-scaling cases more frequently. Also limit
> -		 * scaling to 3x to avoid agressive filtering that makes
> -		 * comparison less reliable, and don't go above 2x downsampling
> -		 * to avoid possible hw limitations.
> -		 */
> -
> -		ratio = ((double) *crtc_w / *src_w);
> -		if (ratio < 0.5)
> -			*src_w = *crtc_w * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_w = *src_w;
> -		else if (ratio > 3.0)
> -			*crtc_w = *src_w * 3;
> -
> -		ratio = ((double) *crtc_h / *src_h);
> -		if (ratio < 0.5)
> -			*src_h = *crtc_h * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_h = *src_h;
> -		else if (ratio > 3.0)
> -			*crtc_h = *src_h * 3;
> -	} else {
> -		*crtc_w = *src_w;
> -		*crtc_h = *src_h;
> -	}
> -
> -	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> -		/*
> -		 * When scaling is involved, make sure to not go off-bounds or
> -		 * scaled clipping may result in decimal dimensions, that most
> -		 * drivers don't support.
> -		 */
> -		if (*crtc_w < mode->hdisplay)
> -			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> -		else
> -			*crtc_x = 0;
> -
> -		if (*crtc_h < mode->vdisplay)
> -			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> -		else
> -			*crtc_y = 0;
> -	} else {
> -		/*
> -		 * Randomize the on-crtc position and allow the plane to go
> -		 * off-display by less than half of its on-crtc dimensions.
> -		 */
> -		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> -		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> -	}
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
> -			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
> -	ret = igt_display_try_commit_atomic(&data->display,
> -					    DRM_MODE_ATOMIC_TEST_ONLY |
> -					    DRM_MODE_ATOMIC_ALLOW_MODESET,
> -					    NULL);
> -	if (!ret)
> -		return;
> -
> -	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
> -	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
> -
> -	/* Make YUV coordinates a multiple of 2 and retry the math. */
> -	if (is_yuv) {
> -		*src_x &= ~1;
> -		*src_y &= ~1;
> -		*src_w &= ~1;
> -		*src_h &= ~1;
> -		/* To handle 1:1 scaling, clear crtc_w/h too. */
> -		*crtc_w &= ~1;
> -		*crtc_h &= ~1;
> -
> -		if (*crtc_x < 0 && (*crtc_x & 1))
> -			(*crtc_x)++;
> -		else
> -			*crtc_x &= ~1;
> -
> -		/* If negative, round up to 0 instead of down */
> -		if (*crtc_y < 0 && (*crtc_y & 1))
> -			(*crtc_y)++;
> -		else
> -			*crtc_y &= ~1;
> -
> -		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -				*crtc_h, *crtc_x, *crtc_y, fb);
> -		ret = igt_display_try_commit_atomic(&data->display,
> -						DRM_MODE_ATOMIC_TEST_ONLY |
> -						DRM_MODE_ATOMIC_ALLOW_MODESET,
> -						NULL);
> -		if (!ret)
> -			return;
> -	}
> -
> -	igt_assert(!ret || allow_scaling);
> -	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> -		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
> -
> -	*crtc_w = *src_w;
> -	*crtc_h = *src_h;
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -			*crtc_h, *crtc_x, *crtc_y, fb);
> -	igt_display_commit_atomic(&data->display,
> -				  DRM_MODE_ATOMIC_TEST_ONLY |
> -				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> -}
> -
> -static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
> -			     uint32_t src_w, uint32_t src_h,
> -			     uint32_t src_x, uint32_t src_y,
> -			     uint32_t crtc_w, uint32_t crtc_h,
> -			     int32_t crtc_x, int32_t crtc_y,
> -			     struct igt_fb *fb)
> -{
> -	cairo_surface_t *surface;
> -	cairo_surface_t *clipped_surface;
> -	cairo_t *cr;
> -
> -	surface = igt_get_cairo_surface(data->drm_fd, fb);
> -
> -	if (src_x || src_y) {
> -		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> -							     src_w, src_h);
> -
> -		cr = cairo_create(clipped_surface);
> -
> -		cairo_translate(cr, -1. * src_x, -1. * src_y);
> -
> -		cairo_set_source_surface(cr, surface, 0, 0);
> -
> -		cairo_paint(cr);
> -		cairo_surface_flush(clipped_surface);
> -
> -		cairo_destroy(cr);
> -	} else {
> -		clipped_surface = surface;
> -	}
> -
> -	cr = cairo_create(result);
> -
> -	cairo_translate(cr, crtc_x, crtc_y);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_scale(cr, (double) crtc_w / src_w,
> -			    (double) crtc_h / src_h);
> -	}
> -
> -	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> -	cairo_surface_destroy(clipped_surface);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_pattern_set_filter(cairo_get_source(cr),
> -					 CAIRO_FILTER_BILINEAR);
> -		cairo_pattern_set_extend(cairo_get_source(cr),
> -					 CAIRO_EXTEND_NONE);
> -	}
> -
> -	cairo_paint(cr);
> -	cairo_surface_flush(result);
> -
> -	cairo_destroy(cr);
> -}
> -
> -static void prepare_randomized_plane(data_t *data,
> -				     drmModeModeInfo *mode,
> -				     igt_plane_t *plane,
> -				     struct igt_fb *overlay_fb,
> -				     unsigned int index,
> -				     cairo_surface_t *result_surface,
> -				     bool allow_scaling, bool allow_yuv)
> -{
> -	struct igt_fb pattern_fb;
> -	uint32_t overlay_fb_w, overlay_fb_h;
> -	uint32_t overlay_src_w, overlay_src_h;
> -	uint32_t overlay_src_x, overlay_src_y;
> -	int32_t overlay_crtc_x, overlay_crtc_y;
> -	uint32_t overlay_crtc_w, overlay_crtc_h;
> -	uint32_t format;
> -	uint64_t modifier;
> -	size_t stride;
> -	bool tiled;
> -	int fb_id;
> -
> -	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> -			      &format, &modifier, allow_yuv);
> -
> -	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> -	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
> -		  index, overlay_fb_w, overlay_fb_h,
> -		  igt_format_str(format), tiled ? "tiled" : "linear");
> -
> -	/* Get a pattern framebuffer for the overlay plane. */
> -	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> -					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
> -			       format, modifier, &stride);
> -
> -	igt_debug("Plane %d: stride %ld\n", index, stride);
> -
> -	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> -					   modifier, stride);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> -				    &overlay_src_w, &overlay_src_h,
> -				    &overlay_src_x, &overlay_src_y,
> -				    &overlay_crtc_w, &overlay_crtc_h,
> -				    &overlay_crtc_x, &overlay_crtc_y,
> -				    allow_scaling);
> -
> -	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
> -		  overlay_src_w, overlay_src_h);
> -	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> -		  overlay_src_x, overlay_src_y);
> -	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
> -		  overlay_crtc_w, overlay_crtc_h);
> -	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
> -		  overlay_crtc_x, overlay_crtc_y);
> -
> -	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> -			 overlay_src_x, overlay_src_y,
> -			 overlay_crtc_w, overlay_crtc_h,
> -			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
> -
> -	/* Remove the original pattern framebuffer. */
> -	igt_remove_fb(data->drm_fd, &pattern_fb);
> -}
> -
> -static const char test_display_planes_random_desc[] =
> -	"Setup a few overlay planes with random parameters, capture the frame "
> -	"and check it matches the expected output";
> -static void test_display_planes_random(data_t *data,
> -				       struct chamelium_port *port,
> -				       enum chamelium_check check)
> -{
> -	igt_output_t *output;
> -	drmModeModeInfo *mode;
> -	igt_plane_t *primary_plane;
> -	struct igt_fb primary_fb;
> -	struct igt_fb result_fb;
> -	struct igt_fb *overlay_fbs;
> -	igt_crc_t *crc;
> -	igt_crc_t *expected_crc;
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	unsigned int overlay_planes_max = 0;
> -	unsigned int overlay_planes_count;
> -	cairo_surface_t *result_surface;
> -	int captured_frame_count;
> -	bool allow_scaling;
> -	bool allow_yuv;
> -	unsigned int i;
> -	unsigned int fb_id;
> -
> -	switch (check) {
> -	case CHAMELIUM_CHECK_CRC:
> -		allow_scaling = false;
> -		allow_yuv = false;
> -		break;
> -	case CHAMELIUM_CHECK_CHECKERBOARD:
> -		allow_scaling = true;
> -		allow_yuv = true;
> -		break;
> -	default:
> -		igt_assert(false);
> -	}
> -
> -	srand(time(NULL));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Find the connector and pipe. */
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -
> -	mode = igt_output_get_mode(output);
> -
> -	/* Get a framebuffer for the primary plane. */
> -	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary_plane);
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> -	igt_assert(fb_id > 0);
> -
> -	/* Get a framebuffer for the cairo composition result. */
> -	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
> -			      mode->vdisplay, DRM_FORMAT_XRGB8888,
> -			      DRM_FORMAT_MOD_LINEAR, &result_fb);
> -	igt_assert(fb_id > 0);
> -
> -	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> -
> -	/* Paint the primary framebuffer on the result surface. */
> -	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> -			 &primary_fb);
> -
> -	/* Configure the primary plane. */
> -	igt_plane_set_fb(primary_plane, &primary_fb);
> -
> -	overlay_planes_max =
> -		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> -
> -	/* Limit the number of planes to a reasonable scene. */
> -	overlay_planes_max = min(overlay_planes_max, 4u);
> -
> -	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> -	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> -
> -	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> -
> -	for (i = 0; i < overlay_planes_count; i++) {
> -		struct igt_fb *overlay_fb = &overlay_fbs[i];
> -		igt_plane_t *plane =
> -			igt_output_get_plane_type_index(output,
> -							DRM_PLANE_TYPE_OVERLAY,
> -							i);
> -		igt_assert(plane);
> -
> -		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> -					 result_surface, allow_scaling,
> -					 allow_yuv);
> -	}
> -
> -	cairo_surface_destroy(result_surface);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&result_fb);
> -
> -	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == 1);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		chamelium_assert_crc_eq_or_dump(data->chamelium,
> -						expected_crc, crc,
> -						&result_fb, 0);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &result_fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	for (i = 0; i < overlay_planes_count; i++)
> -		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> -
> -	free(overlay_fbs);
> -
> -	igt_remove_fb(data->drm_fd, &primary_fb);
> -	igt_remove_fb(data->drm_fd, &result_fb);
> -}
> -
> -static const char test_hpd_without_ddc_desc[] =
> -	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> -static void
> -test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -	igt_flush_uevents(mon);
> -
> -	/* Disable the DDC on the connector and make sure we still get a
> -	 * hotplug
> -	 */
> -	chamelium_port_set_ddc_state(data->chamelium, port, false);
> -	chamelium_plug(data->chamelium, port);
> -
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -						  data->chamelium, port),
> -						  DRM_MODE_CONNECTED);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_hpd_storm_detect_desc[] =
> -	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> -	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> -	"storm";
> -static void
> -test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
> -{
> -	struct udev_monitor *mon;
> -	int count = 0;
> -
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> -
> -	mon = igt_watch_uevents();
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -
> -	/*
> -	 * Polling should have been enabled by the HPD storm at this point,
> -	 * so we should only get at most 1 hotplug event
> -	 */
> -	igt_until_timeout(5)
> -		count += igt_hotplug_detected(mon, 1);
> -	igt_assert_lt(count, 2);
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_hpd_storm_disable_desc[] =
> -	"Disable HPD storm detection, trigger a storm and check the kernel "
> -	"doesn't detect one";
> -static void
> -test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
> -{
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	chamelium_fire_hpd_pulses(data->chamelium, port,
> -				  width, 10);
> -	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> -
> -	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,
> -				   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;
> -
> -		monitor_edid *edid = &edids_list[i];
> -		igt_info("Testing out the EDID for %s\n",
> -			 monitor_edid_get_name(edid));
> -
> -		/* Getting and Setting the EDID on Chamelium. */
> -		chamelium_edid =
> -			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> -}
> -
> -static const char igt_edid_resolution_list_desc[] =
> -	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> -	" screen resolution matches the mode resolution.";
> -
> -static void edid_resolution_list(data_t *data, struct chamelium_port *port)
> -{
> -	struct chamelium *chamelium = data->chamelium;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	drmModeConnector *connector;
> -	drmModeModeInfoPtr modes;
> -	int count_modes;
> -	int i;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	chamelium_unplug(chamelium, port);
> -	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> -
> -	igt_flush_uevents(mon);
> -	chamelium_plug(chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
> -	igt_flush_uevents(mon);
> -
> -	connector = chamelium_port_get_connector(chamelium, port, true);
> -	modes = connector->modes;
> -	count_modes = connector->count_modes;
> -
> -	output = get_output_for_port(data, port);
> -	pipe = get_pipe_for_output(&data->display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	for (i = 0; i < count_modes; ++i)
> -		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> -
> -	for (i = 0; i < count_modes; ++i) {
> -		struct igt_fb fb = { 0 };
> -		bool is_video_stable;
> -		int screen_res_w, screen_res_h;
> -
> -		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> -			 modes[i].vrefresh);
> -
> -		/* Set the screen mode with the one we chose. */
> -		create_fb_for_mode(data, &fb, &modes[i]);
> -		enable_output(data, port, output, &modes[i], &fb);
> -		is_video_stable = chamelium_port_wait_video_input_stable(
> -			chamelium, port, 10);
> -		igt_assert(is_video_stable);
> -
> -		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> -					      &screen_res_h);
> -		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> -		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	drmModeFreeConnector(connector);
> -}
> -
> -#define for_each_port(p, port)            \
> -	for (p = 0, port = data.ports[p]; \
> -	     p < data.port_count;         \
> -	     p++, port = data.ports[p])
> -
> -#define connector_subtest(name__, type__)                    \
> -	igt_subtest(name__)                                  \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -#define connector_dynamic_subtest(name__, type__)            \
> -	igt_subtest_with_dynamic(name__)                     \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -
> -static data_t data;
> -
> -IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> -igt_main
> -{
> -	struct chamelium_port *port;
> -	int p;
> -	size_t i;
> -
> -	igt_fixture {
> -		/* So fbcon doesn't try to reprobe things itself */
> -		kmstest_set_vt_graphics_mode();
> -
> -		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
> -		igt_display_require(&data.display, data.drm_fd);
> -		igt_require(data.display.is_atomic);
> -
> -		/*
> -		 * XXX: disabling modeset, can be removed when
> -		 * igt_display_require will start doing this for us
> -		 */
> -		igt_display_commit2(&data.display, COMMIT_ATOMIC);
> -
> -		/* we need to initalize chamelium after igt_display_require */
> -		data.chamelium = chamelium_init(data.drm_fd, &data.display);
> -		igt_require(data.chamelium);
> -
> -		data.ports = chamelium_get_ports(data.chamelium,
> -						 &data.port_count);
> -
> -		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> -			data.edids[i] = chamelium_new_edid(data.chamelium,
> -							   igt_kms_get_custom_edid(i));
> -		}
> -	}
> -
> -	igt_describe("DisplayPort tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-fast", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("dp-edid-read", DisplayPort) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> -					       ARRAY_SIZE(DP_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-non-4k",
> -				  DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> -					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> -
> -		igt_describe(igt_edid_resolution_list_desc);
> -		connector_subtest("dp-edid-resolution-list", DisplayPort)
> -			edid_resolution_list(&data, port);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("dp-hpd-storm", DisplayPort)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-single", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("dp-crc-fast", DisplayPort)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-multiple", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("dp-frame-dump", DisplayPort)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("dp-mode-timings", DisplayPort)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("dp-audio", DisplayPort)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("dp-audio-edid", DisplayPort)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("HDMI tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-fast", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("hdmi-edid-read", HDMIA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("hdmi-hpd-storm", HDMIA)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-single", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("hdmi-crc-fast", HDMIA)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-multiple", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CRC, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-crc-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CRC);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (!igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CHECKERBOARD);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("hdmi-frame-dump", HDMIA)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("hdmi-mode-timings", HDMIA)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("hdmi-audio", HDMIA)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("hdmi-audio-edid", HDMIA)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_aspect_ratio_desc);
> -		connector_subtest("hdmi-aspect-ratio", HDMIA)
> -			test_display_aspect_ratio(&data, port);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("VGA tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-fast", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("vga-edid-read", VGA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-suspend", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-hibernate", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_without_ddc_desc);
> -		connector_subtest("vga-hpd-without-ddc", VGA)
> -			test_hpd_without_ddc(&data, port);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("vga-frame-dump", VGA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_ANALOG, 1);
> -	}
> -
> -	igt_describe("Tests that operate on all connectors");
> -	igt_subtest_group {
> -
> -		igt_fixture {
> -			igt_require(data.port_count);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-suspend")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_MEM,
> -						       SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-hibernate")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_DISK,
> -						       SUSPEND_TEST_DEVICES);
> -	}
> -
> -	igt_describe(test_hotplug_for_each_pipe_desc);
> -	connector_subtest("vga-hpd-for-each-pipe", VGA)
> -		test_hotplug_for_each_pipe(&data, port);
> -
> -	igt_fixture {
> -		igt_display_fini(&data.display);
> -		close(data.drm_fd);
> -	}
> -}
> diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
> new file mode 100644
> index 00000000..4d13744c
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_audio.c
> @@ -0,0 +1,858 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the Audio functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +/* Playback parameters control the audio signal we synthesize and send */
> +#define PLAYBACK_CHANNELS 2
> +#define PLAYBACK_SAMPLES 1024
> +
> +/* Capture paremeters control the audio signal we receive */
> +#define CAPTURE_SAMPLES 2048
> +
> +#define AUDIO_TIMEOUT 2000 /* ms */
> +/* A streak of 3 gives confidence that the signal is good. */
> +#define MIN_STREAK 3
> +
> +#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> +#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> +#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> +
> +struct audio_state {
> +	struct alsa *alsa;
> +	struct chamelium *chamelium;
> +	struct chamelium_port *port;
> +	struct chamelium_stream *stream;
> +
> +	/* The capture format is only available after capture has started. */
> +	struct {
> +		snd_pcm_format_t format;
> +		int channels;
> +		int rate;
> +	} playback, capture;
> +
> +	char *name;
> +	struct audio_signal *signal; /* for frequencies test only */
> +	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	size_t recv_pages;
> +	int msec;
> +
> +	int dump_fd;
> +	char *dump_path;
> +
> +	pthread_t thread;
> +	atomic_bool run;
> +	atomic_bool positive; /* for pulse test only */
> +};
> +
> +/* TODO: enable >48KHz rates, these are not reliable */
> +static int test_sampling_rates[] = {
> +	32000, 44100, 48000,
> +	/* 88200, */
> +	/* 96000, */
> +	/* 176400, */
> +	/* 192000, */
> +};
> +
> +static int test_sampling_rates_count =
> +	sizeof(test_sampling_rates) / sizeof(int);
> +
> +/* Test frequencies (Hz): a sine signal will be generated for each.
> + *
> + * Depending on the sampling rate chosen, it might not be possible to properly
> + * detect the generated sine (see Nyquist–Shannon sampling theorem).
> + * Frequencies that can't be reliably detected will be automatically pruned in
> + * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> + * tested with a 192KHz sampling rate.
> + */
> +static int test_frequencies[] = {
> +	300, 600, 1200, 10000, 80000,
> +};
> +
> +static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> +
> +static const snd_pcm_format_t test_formats[] = {
> +	SND_PCM_FORMAT_S16_LE,
> +	SND_PCM_FORMAT_S24_LE,
> +	SND_PCM_FORMAT_S32_LE,
> +};
> +
> +static const size_t test_formats_count =
> +	sizeof(test_formats) / sizeof(test_formats[0]);
> +
> +static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
> +			     struct alsa *alsa, struct chamelium_port *port,
> +			     snd_pcm_format_t format, int channels, int rate)
> +{
> +	memset(state, 0, sizeof(*state));
> +	state->dump_fd = -1;
> +
> +	state->alsa = alsa;
> +	state->chamelium = data->chamelium;
> +	state->port = port;
> +
> +	state->playback.format = format;
> +	state->playback.channels = channels;
> +	state->playback.rate = rate;
> +
> +	alsa_configure_output(alsa, format, channels, rate);
> +
> +	state->stream = chamelium_stream_init();
> +	igt_assert_f(state->stream,
> +		     "Failed to initialize Chamelium stream client\n");
> +}
> +
> +static void audio_state_fini(struct audio_state *state)
> +{
> +	chamelium_stream_deinit(state->stream);
> +	free(state->name);
> +}
> +
> +static void *run_audio_thread(void *data)
> +{
> +	struct alsa *alsa = data;
> +
> +	alsa_run(alsa, -1);
> +	return NULL;
> +}
> +
> +static void audio_state_start(struct audio_state *state, const char *name)
> +{
> +	int ret;
> +	bool ok;
> +	size_t i, j;
> +	enum chamelium_stream_realtime_mode stream_mode;
> +	char dump_suffix[64];
> +
> +	free(state->name);
> +	state->name = strdup(name);
> +	state->recv_pages = 0;
> +	state->msec = 0;
> +
> +	igt_debug("Starting %s test with playback format %s, "
> +		  "sampling rate %d Hz and %d channels\n",
> +		  name, snd_pcm_format_name(state->playback.format),
> +		  state->playback.rate, state->playback.channels);
> +
> +	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> +
> +	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> +	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> +	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> +
> +	/* Start playing audio */
> +	state->run = true;
> +	ret = pthread_create(&state->thread, NULL, run_audio_thread,
> +			     state->alsa);
> +	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> +
> +	/* The Chamelium device only supports this PCM format. */
> +	state->capture.format = SND_PCM_FORMAT_S32_LE;
> +
> +	/* Only after we've started playing audio, we can retrieve the capture
> +	 * format used by the Chamelium device. */
> +	chamelium_get_audio_format(state->chamelium, state->port,
> +				   &state->capture.rate,
> +				   &state->capture.channels);
> +	if (state->capture.rate == 0) {
> +		igt_debug("Audio receiver doesn't indicate the capture "
> +			  "sampling rate, assuming it's %d Hz\n",
> +			  state->playback.rate);
> +		state->capture.rate = state->playback.rate;
> +	}
> +
> +	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> +					    state->channel_mapping);
> +	/* Make sure we can capture all channels we send. */
> +	for (i = 0; i < state->playback.channels; i++) {
> +		ok = false;
> +		for (j = 0; j < state->capture.channels; j++) {
> +			if (state->channel_mapping[j] == i) {
> +				ok = true;
> +				break;
> +			}
> +		}
> +		igt_assert_f(ok, "Cannot capture all channels\n");
> +	}
> +
> +	if (igt_frame_dump_is_enabled()) {
> +		snprintf(dump_suffix, sizeof(dump_suffix),
> +			 "capture-%s-%s-%dch-%dHz", name,
> +			 snd_pcm_format_name(state->playback.format),
> +			 state->playback.channels, state->playback.rate);
> +
> +		state->dump_fd = audio_create_wav_file_s32_le(
> +			dump_suffix, state->capture.rate,
> +			state->capture.channels, &state->dump_path);
> +		igt_assert_f(state->dump_fd >= 0,
> +			     "Failed to create audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_receive(struct audio_state *state, int32_t **recv,
> +				size_t *recv_len)
> +{
> +	bool ok;
> +	size_t page_count;
> +	size_t recv_size;
> +
> +	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
> +						     recv, recv_len);
> +	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> +
> +	state->msec = state->recv_pages * *recv_len /
> +		      (double)state->capture.channels /
> +		      (double)state->capture.rate * 1000;
> +	state->recv_pages++;
> +
> +	if (state->dump_fd >= 0) {
> +		recv_size = *recv_len * sizeof(int32_t);
> +		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
> +				     recv_size,
> +			     "Failed to write to audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_stop(struct audio_state *state, bool success)
> +{
> +	bool ok;
> +	int ret;
> +	struct chamelium_audio_file *audio_file;
> +	enum igt_log_level log_level;
> +
> +	igt_debug("Stopping audio playback\n");
> +	state->run = false;
> +	ret = pthread_join(state->thread, NULL);
> +	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> +
> +	ok = chamelium_stream_stop_realtime_audio(state->stream);
> +	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> +
> +	audio_file =
> +		chamelium_stop_capturing_audio(state->chamelium, state->port);
> +	if (audio_file) {
> +		igt_debug("Audio file saved on the Chamelium in %s\n",
> +			  audio_file->path);
> +		chamelium_destroy_audio_file(audio_file);
> +	}
> +
> +	if (state->dump_fd >= 0) {
> +		close(state->dump_fd);
> +		state->dump_fd = -1;
> +
> +		if (success) {
> +			/* Test succeeded, no need to keep the captured data */
> +			unlink(state->dump_path);
> +		} else
> +			igt_debug("Saved captured audio data to %s\n",
> +				  state->dump_path);
> +		free(state->dump_path);
> +		state->dump_path = NULL;
> +	}
> +
> +	if (success)
> +		log_level = IGT_LOG_DEBUG;
> +	else
> +		log_level = IGT_LOG_CRITICAL;
> +
> +	igt_log(IGT_LOG_DOMAIN, log_level,
> +		"Audio %s test result for format %s, "
> +		"sampling rate %d Hz and %d channels: %s\n",
> +		state->name, snd_pcm_format_name(state->playback.format),
> +		state->playback.rate, state->playback.channels,
> +		success ? "ALL GREEN" : "FAILED");
> +}
> +
> +static void check_audio_infoframe(struct audio_state *state)
> +{
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_audio infoframe_audio;
> +	struct infoframe_audio expected = { 0 };
> +	bool ok;
> +
> +	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "Chamelium board doesn't support GetLastInfoFrame\n");
> +		return;
> +	}
> +
> +	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> +	expected.channel_count = state->playback.channels;
> +	expected.sampling_freq = state->playback.rate;
> +	expected.sample_size = snd_pcm_format_width(state->playback.format);
> +
> +	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> +						 CHAMELIUM_INFOFRAME_AUDIO);
> +	if (infoframe == NULL && state->playback.channels <= 2) {
> +		/* Audio InfoFrames are optional for mono and stereo audio */
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "no InfoFrame received\n");
> +		return;
> +	}
> +	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> +
> +	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> +				   infoframe->payload, infoframe->payload_size);
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> +
> +	igt_debug("Checking audio InfoFrame:\n");
> +	igt_debug("coding_type: got %d, expected %d\n",
> +		  infoframe_audio.coding_type, expected.coding_type);
> +	igt_debug("channel_count: got %d, expected %d\n",
> +		  infoframe_audio.channel_count, expected.channel_count);
> +	igt_debug("sampling_freq: got %d, expected %d\n",
> +		  infoframe_audio.sampling_freq, expected.sampling_freq);
> +	igt_debug("sample_size: got %d, expected %d\n",
> +		  infoframe_audio.sample_size, expected.sample_size);
> +
> +	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> +		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> +	if (infoframe_audio.channel_count >= 0)
> +		igt_assert(infoframe_audio.channel_count ==
> +			   expected.channel_count);
> +	if (infoframe_audio.sampling_freq >= 0)
> +		igt_assert(infoframe_audio.sampling_freq ==
> +			   expected.sampling_freq);
> +	if (infoframe_audio.sample_size >= 0)
> +		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> +}
> +
> +static int audio_output_frequencies_callback(void *data, void *buffer,
> +					     int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	audio_signal_fill(state->signal, tmp, samples);
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool test_audio_frequencies(struct audio_state *state)
> +{
> +	int freq, step;
> +	int32_t *recv, *buf;
> +	double *channel;
> +	size_t i, j, streak;
> +	size_t recv_len, buf_len, buf_cap, channel_len;
> +	bool success;
> +	int capture_chan;
> +
> +	state->signal = audio_signal_init(state->playback.channels,
> +					  state->playback.rate);
> +	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> +
> +	/* We'll choose different frequencies per channel to make sure they are
> +	 * independent from each other. To do so, we'll add a different offset
> +	 * to the base frequencies for each channel. We need to choose a big
> +	 * enough offset so that we're sure to detect mixed up channels. We
> +	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> +	 * difference.
> +	 *
> +	 * Note that we assume capture_rate == playback_rate. We'll assert this
> +	 * later on. We cannot retrieve the capture rate before starting
> +	 * playing audio, so we don't really have the choice.
> +	 */
> +	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> +	for (i = 0; i < test_frequencies_count; i++) {
> +		for (j = 0; j < state->playback.channels; j++) {
> +			freq = test_frequencies[i] + j * step;
> +			audio_signal_add_frequency(state->signal, freq, j);
> +		}
> +	}
> +	audio_signal_synthesize(state->signal);
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_frequencies_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	audio_state_start(state, "frequencies");
> +
> +	igt_assert_f(state->capture.rate == state->playback.rate,
> +		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> +		     state->capture.rate, state->playback.rate);
> +
> +	/* Needs to be a multiple of 128, because that's the number of samples
> +	 * we get per channel each time we receive an audio page from the
> +	 * Chamelium device.
> +	 *
> +	 * Additionally, this value needs to be high enough to guarantee we
> +	 * capture a full period of each sine we generate. If we capture 2048
> +	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> +	 * sines. For lower sampling rates, the capture duration will be
> +	 * longer.
> +	 */
> +	channel_len = CAPTURE_SAMPLES;
> +	channel = malloc(sizeof(double) * channel_len);
> +
> +	buf_cap = state->capture.channels * channel_len;
> +	buf = malloc(sizeof(int32_t) * buf_cap);
> +	buf_len = 0;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +
> +	success = false;
> +	streak = 0;
> +	while (!success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> +		buf_len += recv_len;
> +
> +		if (buf_len < buf_cap)
> +			continue;
> +		igt_assert(buf_len == buf_cap);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (j = 0; j < state->playback.channels; j++) {
> +			capture_chan = state->channel_mapping[j];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  j, capture_chan);
> +
> +			audio_extract_channel_s32_le(channel, channel_len, buf,
> +						     buf_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			if (audio_signal_detect(state->signal,
> +						state->capture.rate, j, channel,
> +						channel_len))
> +				streak++;
> +			else
> +				streak = 0;
> +		}
> +
> +		buf_len = 0;
> +
> +		success = streak == MIN_STREAK * state->playback.channels;
> +	}
> +
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +	free(buf);
> +	free(channel);
> +	audio_signal_fini(state->signal);
> +
> +	check_audio_infoframe(state);
> +
> +	return success;
> +}
> +
> +static int audio_output_flatline_callback(void *data, void *buffer, int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len, i;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	for (i = 0; i < len; i++)
> +		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> +{
> +	double expected, min, max;
> +	size_t i;
> +	bool ok;
> +
> +	min = max = NAN;
> +	for (i = 0; i < buf_len; i++) {
> +		if (isnan(min) || buf[i] < min)
> +			min = buf[i];
> +		if (isnan(max) || buf[i] > max)
> +			max = buf[i];
> +	}
> +
> +	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> +	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> +	if (ok)
> +		igt_debug("Flatline wave amplitude detected\n");
> +	else
> +		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> +			  min, max);
> +	return ok;
> +}
> +
> +static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> +{
> +	size_t i;
> +
> +	for (i = 0; i < buf_len; i++) {
> +		if (buf[i] < 0)
> +			return i;
> +	}
> +
> +	return -1;
> +}
> +
> +/** test_audio_flatline:
> + *
> + * Send a constant value (one positive, then a negative one) and check that:
> + *
> + * - The amplitude of the flatline is correct
> + * - All channels switch from a positive signal to a negative one at the same
> + *   time (ie. all channels are aligned)
> + */
> +static bool test_audio_flatline(struct audio_state *state)
> +{
> +	bool success, amp_success, align_success;
> +	int32_t *recv;
> +	size_t recv_len, i, channel_len;
> +	ssize_t j;
> +	int streak, capture_chan;
> +	double *channel;
> +	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_flatline_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	/* Start by sending a positive signal */
> +	state->positive = true;
> +
> +	audio_state_start(state, "flatline");
> +
> +	for (i = 0; i < state->playback.channels; i++)
> +		falling_edges[i] = -1;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +	amp_success = false;
> +	streak = 0;
> +	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (i = 0; i < state->playback.channels; i++) {
> +			capture_chan = state->channel_mapping[i];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  i, capture_chan);
> +
> +			channel_len = audio_extract_channel_s32_le(
> +				NULL, 0, recv, recv_len,
> +				state->capture.channels, capture_chan);
> +			channel = malloc(channel_len * sizeof(double));
> +			audio_extract_channel_s32_le(channel, channel_len, recv,
> +						     recv_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			/* Check whether the amplitude is fine */
> +			if (detect_flatline_amplitude(channel, channel_len,
> +						      state->positive))
> +				streak++;
> +			else
> +				streak = 0;
> +
> +			/* If we're now sending a negative signal, detect the
> +			 * falling edge */
> +			j = detect_falling_edge(channel, channel_len);
> +			if (!state->positive && j >= 0) {
> +				falling_edges[i] =
> +					recv_len * state->recv_pages + j;
> +			}
> +
> +			free(channel);
> +		}
> +
> +		amp_success = streak == MIN_STREAK * state->playback.channels;
> +
> +		if (amp_success && state->positive) {
> +			/* Switch to a negative signal after we've detected the
> +			 * positive one. */
> +			state->positive = false;
> +			amp_success = false;
> +			streak = 0;
> +			igt_debug("Switching to negative square wave\n");
> +		}
> +	}
> +
> +	/* Check alignment between all channels by comparing the index of the
> +	 * falling edge. */
> +	align_success = true;
> +	for (i = 0; i < state->playback.channels; i++) {
> +		if (falling_edges[i] < 0) {
> +			igt_critical(
> +				"Falling edge not detected for channel %zu\n",
> +				i);
> +			align_success = false;
> +			continue;
> +		}
> +
> +		if (abs(falling_edges[0] - falling_edges[i]) >
> +		    FLATLINE_ALIGN_ACCURACY) {
> +			igt_critical("Channel alignment mismatch: "
> +				     "channel 0 has a falling edge at index %d "
> +				     "while channel %zu has index %d\n",
> +				     falling_edges[0], i, falling_edges[i]);
> +			align_success = false;
> +		}
> +	}
> +
> +	success = amp_success && align_success;
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +
> +	return success;
> +}
> +
> +static bool check_audio_configuration(struct alsa *alsa,
> +				      snd_pcm_format_t format, int channels,
> +				      int sampling_rate)
> +{
> +	if (!alsa_test_output_configuration(alsa, format, channels,
> +					    sampling_rate)) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because at least one of the "
> +			  "selected output devices doesn't support this "
> +			  "configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	/* TODO: the Chamelium device sends a malformed signal for some audio
> +	 * configurations. See crbug.com/950917 */
> +	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> +	    channels > 2) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because the Chamelium device "
> +			  "doesn't support this configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	return true;
> +}
> +
> +static const char test_display_audio_desc[] =
> +	"Playback various audio signals with various audio formats/rates, "
> +	"capture them and check they are correct";
> +static void test_display_audio(chamelium_data_t *data,
> +			       struct chamelium_port *port,
> +			       const char *audio_device,
> +			       enum igt_custom_edid_type edid)
> +{
> +	bool run, success;
> +	struct alsa *alsa;
> +	int ret;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id, i, j;
> +	int channels, sampling_rate;
> +	snd_pcm_format_t format;
> +	struct audio_state state;
> +
> +	igt_require(alsa_has_exclusive_access());
> +
> +	/* Old Chamelium devices need an update for DisplayPort audio and
> +	 * chamelium_get_audio_format support. */
> +	igt_require(chamelium_has_audio_support(data->chamelium, port));
> +
> +	alsa = alsa_init();
> +	igt_assert(alsa);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because the receiver won't try to receive audio if
> +	 * it doesn't receive video. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	run = false;
> +	success = true;
> +	for (i = 0; i < test_sampling_rates_count; i++) {
> +		for (j = 0; j < test_formats_count; j++) {
> +			ret = alsa_open_output(alsa, audio_device);
> +			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> +
> +			/* TODO: playback on all 8 available channels (this
> +			 * isn't supported by Chamelium devices yet, see
> +			 * https://crbug.com/950917) */
> +			format = test_formats[j];
> +			channels = PLAYBACK_CHANNELS;
> +			sampling_rate = test_sampling_rates[i];
> +
> +			if (!check_audio_configuration(alsa, format, channels,
> +						       sampling_rate))
> +				continue;
> +
> +			run = true;
> +
> +			audio_state_init(&state, data, alsa, port, format,
> +					 channels, sampling_rate);
> +			success &= test_audio_frequencies(&state);
> +			success &= test_audio_flatline(&state);
> +			audio_state_fini(&state);
> +
> +			alsa_close_output(alsa);
> +		}
> +	}
> +
> +	/* Make sure we tested at least one frequency and format. */
> +	igt_assert(run);
> +	/* Make sure all runs were successful. */
> +	igt_assert(success);
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +
> +	free(alsa);
> +}
> +
> +static const char test_display_audio_edid_desc[] =
> +	"Plug a connector with an EDID suitable for audio, check ALSA's "
> +	"EDID-Like Data reports the correct audio parameters";
> +static void test_display_audio_edid(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_custom_edid_type edid)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id;
> +	struct eld_entry eld;
> +	struct eld_sad *sad;
> +
> +	igt_require(eld_is_supported());
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because audio cannot be played on inactive
> +	 * connectors. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	igt_assert(eld_get_igt(&eld));
> +	igt_assert(eld.sads_len == 1);
> +
> +	sad = &eld.sads[0];
> +	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> +	igt_assert(sad->channels == 2);
> +	igt_assert(sad->rates ==
> +		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
> +		    CEA_SAD_SAMPLING_RATE_48KHZ));
> +	igt_assert(sad->bits ==
> +		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
> +		    CEA_SAD_SAMPLE_SIZE_24));
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("dp-audio", DisplayPort) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("dp-audio-edid", DisplayPort)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_DP_AUDIO);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("hdmi-audio-edid", HDMIA)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_HDMI_AUDIO);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
> similarity index 100%
> rename from tests/chamelium/kms_color_chamelium.c
> rename to tests/chamelium/kms_chamelium_color.c
> diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
> new file mode 100644
> index 00000000..0b28189e
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_edid.c
> @@ -0,0 +1,534 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the EDID functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include <xf86drmMode.h>
> +
> +#include "igt_chamelium.h"
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +#include "monitor_edids/dp_edids.h"
> +#include "monitor_edids/hdmi_edids.h"
> +#include "monitor_edids/monitor_edids_helper.h"
> +
> +#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> +
> +static void get_connectors_link_status_failed(chamelium_data_t *data,
> +					      bool *link_status_failed)
> +{
> +	drmModeConnector *connector;
> +	uint64_t link_status;
> +	drmModePropertyPtr prop;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		connector = chamelium_port_get_connector(data->chamelium,
> +							 data->ports[p], false);
> +
> +		igt_assert(kmstest_get_property(
> +			data->drm_fd, connector->connector_id,
> +			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
> +			&link_status, &prop));
> +
> +		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> +
> +		drmModeFreeProperty(prop);
> +		drmModeFreeConnector(connector);
> +	}
> +}
> +
> +static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> +		       drmModeModeInfo *mode)
> +{
> +	struct chamelium_video_params video_params = { 0 };
> +	double mode_clock;
> +	int mode_hsync_offset, mode_vsync_offset;
> +	int mode_hsync_width, mode_vsync_width;
> +	int mode_hsync_polarity, mode_vsync_polarity;
> +
> +	chamelium_port_get_video_params(chamelium, port, &video_params);
> +
> +	mode_clock = (double)mode->clock / 1000;
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> +		/* this is what chamelium understands as offsets for DP */
> +		mode_hsync_offset = mode->htotal - mode->hsync_start;
> +		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> +	} else {
> +		/* and this is what they are for other connectors */
> +		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> +		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> +	}
> +
> +	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> +	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> +
> +	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> +	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> +
> +	igt_debug("Checking video mode:\n");
> +	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
> +		  mode_clock, MODE_CLOCK_ACCURACY * 100);
> +	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
> +		  mode->hdisplay);
> +	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
> +		  mode->vdisplay);
> +	igt_debug("hsync_offset: got %d, expected %d\n",
> +		  video_params.hsync_offset, mode_hsync_offset);
> +	igt_debug("vsync_offset: got %d, expected %d\n",
> +		  video_params.vsync_offset, mode_vsync_offset);
> +	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
> +		  mode->htotal);
> +	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
> +		  mode->vtotal);
> +	igt_debug("hsync_width: got %d, expected %d\n",
> +		  video_params.hsync_width, mode_hsync_width);
> +	igt_debug("vsync_width: got %d, expected %d\n",
> +		  video_params.vsync_width, mode_vsync_width);
> +	igt_debug("hsync_polarity: got %d, expected %d\n",
> +		  video_params.hsync_polarity, mode_hsync_polarity);
> +	igt_debug("vsync_polarity: got %d, expected %d\n",
> +		  video_params.vsync_polarity, mode_vsync_polarity);
> +
> +	if (!isnan(video_params.clock)) {
> +		igt_assert(video_params.clock >
> +			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> +		igt_assert(video_params.clock <
> +			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> +	}
> +	igt_assert(video_params.hactive == mode->hdisplay);
> +	igt_assert(video_params.vactive == mode->vdisplay);
> +	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> +	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> +	igt_assert(video_params.htotal == mode->htotal);
> +	igt_assert(video_params.vtotal == mode->vtotal);
> +	igt_assert(video_params.hsync_width == mode_hsync_width);
> +	igt_assert(video_params.vsync_width == mode_vsync_width);
> +	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> +	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> +}
> +
> +static const char igt_custom_edid_type_read_desc[] =
> +	"Make sure the EDID exposed by KMS is the same as the screen's";
> +static void igt_custom_edid_type_read(chamelium_data_t *data,
> +				      struct chamelium_port *port,
> +				      enum igt_custom_edid_type edid)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector;
> +	size_t raw_edid_size;
> +	const struct edid *raw_edid;
> +	uint64_t edid_blob_id;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_skip_on(chamelium_check_analog_bridge(data, port));
> +
> +	connector = chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob_id != 0);
> +	igt_assert(edid_blob =
> +			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));

This is still spewing warnings in gitlab-CI that I can't reproduce
locally. The difference to the previous code is the newline after =,
maybe it's just the compiler being blind when that's in a macro...?


-- 
Petri Latvala


> +
> +	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> +	raw_edid_size = edid_get_size(raw_edid);
> +	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +}
> +
> +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(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   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;
> +
> +		monitor_edid *edid = &edids_list[i];
> +		igt_info("Testing out the EDID for %s\n",
> +			 monitor_edid_get_name(edid));
> +
> +		/* Getting and Setting the EDID on Chamelium. */
> +		chamelium_edid =
> +			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> +		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
> +		chamelium_create_fb_for_mode(data, &fb, &mode);
> +		output = chamelium_get_output_for_port(data, port);
> +		pipe = chamelium_get_pipe_for_output(&data->display, output);
> +		igt_output_set_pipe(output, pipe);
> +		chamelium_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);
> +}
> +
> +static const char igt_edid_resolution_list_desc[] =
> +	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> +	" screen resolution matches the mode resolution.";
> +
> +static void edid_resolution_list(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct chamelium *chamelium = data->chamelium;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	drmModeConnector *connector;
> +	drmModeModeInfoPtr modes;
> +	int count_modes;
> +	int i;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	chamelium_unplug(chamelium, port);
> +	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> +
> +	igt_flush_uevents(mon);
> +	chamelium_plug(chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_CONNECTED);
> +	igt_flush_uevents(mon);
> +
> +	connector = chamelium_port_get_connector(chamelium, port, true);
> +	modes = connector->modes;
> +	count_modes = connector->count_modes;
> +
> +	output = chamelium_get_output_for_port(data, port);
> +	pipe = chamelium_get_pipe_for_output(&data->display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	for (i = 0; i < count_modes; ++i)
> +		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> +
> +	for (i = 0; i < count_modes; ++i) {
> +		struct igt_fb fb = { 0 };
> +		bool is_video_stable;
> +		int screen_res_w, screen_res_h;
> +
> +		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> +			 modes[i].vrefresh);
> +
> +		/* Set the screen mode with the one we chose. */
> +		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
> +		chamelium_enable_output(data, port, output, &modes[i], &fb);
> +		is_video_stable = chamelium_port_wait_video_input_stable(
> +			chamelium, port, 10);
> +		igt_assert(is_video_stable);
> +
> +		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> +					      &screen_res_h);
> +		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> +		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_suspend_resume_edid_change_desc[] =
> +	"Simulate a screen being unplugged and another screen being plugged "
> +	"during suspend, check that a uevent is sent and connector status is "
> +	"updated";
> +static void test_suspend_resume_edid_change(chamelium_data_t *data,
> +					    struct chamelium_port *port,
> +					    enum igt_suspend_state state,
> +					    enum igt_suspend_test test,
> +					    enum igt_custom_edid_type edid,
> +					    enum igt_custom_edid_type alt_edid)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	bool link_status_failed[2][data->port_count];
> +	int p;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Catch the event and flush all remaining ones. */
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_flush_uevents(mon);
> +
> +	/* First plug in the port */
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	/*
> +	 * Change the edid before we suspend. On resume, the machine should
> +	 * notice the EDID change and fire a hotplug event.
> +	 */
> +	chamelium_set_edid(data, port, alt_edid);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[0]);
> +
> +	igt_flush_uevents(mon);
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[1]);
> +
> +	for (p = 0; p < data->port_count; p++)
> +		igt_skip_on(!link_status_failed[0][p] &&
> +			    link_status_failed[1][p]);
> +}
> +
> +static const char test_mode_timings_desc[] =
> +	"For each mode of the IGT base EDID, perform a modeset and check the "
> +	"mode detected by the Chamelium receiver matches the mode we set";
> +static void test_mode_timings(chamelium_data_t *data,
> +			      struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	igt_require(chamelium_supports_get_video_params(data->chamelium));
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +		int fb_id;
> +		struct igt_fb fb;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		/* Trigger the FSM */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> +
> +		check_mode(data->chamelium, port, mode);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("dp-edid-read", DisplayPort)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> +					       ARRAY_SIZE(DP_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-non-4k",
> +				  DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> +					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> +
> +		igt_describe(igt_edid_resolution_list_desc);
> +		connector_subtest("dp-edid-resolution-list", DisplayPort)
> +			edid_resolution_list(&data, port);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-hibernate",
> +				  DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("dp-mode-timings", DisplayPort)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("hdmi-edid-read", HDMIA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("hdmi-mode-timings", HDMIA)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("vga-edid-read", VGA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
> new file mode 100644
> index 00000000..008bc34b
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_frames.c
> @@ -0,0 +1,1085 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Lyude Paul <lyude@redhat.com>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +#define connector_dynamic_subtest(name__, type__)                   \
> +	igt_subtest_with_dynamic(name__)                            \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +struct vic_mode {
> +	int hactive, vactive;
> +	int vrefresh; /* Hz */
> +	uint32_t picture_ar;
> +};
> +
> +static int chamelium_vga_modes[][2] = {
> +	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
> +	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
> +	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
> +	{ 640, 480 },	{ -1, -1 },
> +};
> +
> +/* Maps Video Identification Codes to a mode */
> +static const struct vic_mode vic_modes[] = {
> +	[16] = {
> +		.hactive = 1920,
> +		.vactive = 1080,
> +		.vrefresh = 60,
> +		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> +	},
> +};
> +
> +/* Maps aspect ratios to their mode flag */
> +static const uint32_t mode_ar_flags[] = {
> +	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> +};
> +
> +static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
> +{
> +	int i = 0;
> +
> +	while (chamelium_vga_modes[i][0] != -1) {
> +		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> +		    mode->vdisplay == chamelium_vga_modes[i][1])
> +			return false;
> +
> +		i++;
> +	}
> +
> +	return true;
> +}
> +
> +static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
> +			    igt_output_t *output, drmModeModeInfo *mode,
> +			    uint32_t fourcc, enum chamelium_check check,
> +			    int count)
> +{
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	struct igt_fb frame_fb, fb;
> +	int i, fb_id, captured_frame_count;
> +	int frame_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &fb);
> +	igt_assert(fb_id > 0);
> +
> +	frame_id =
> +		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
> +	igt_assert(frame_id > 0);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&fb);
> +
> +	chamelium_enable_output(data, port, output, mode, &frame_fb);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		igt_crc_t *expected_crc;
> +		igt_crc_t *crc;
> +
> +		/* We want to keep the display running for a little bit, since
> +		 * there's always the potential the driver isn't able to keep
> +		 * the display running properly for very long
> +		 */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == count);
> +
> +		igt_debug("Captured %d frames\n", captured_frame_count);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		for (i = 0; i < captured_frame_count; i++)
> +			chamelium_assert_crc_eq_or_dump(
> +				data->chamelium, expected_crc, &crc[i], &fb, i);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> +		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		igt_assert(count == 1);
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG)
> +			chamelium_crop_analog_frame(dump, mode->hdisplay,
> +						    mode->vdisplay);
> +
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	igt_remove_fb(data->drm_fd, &frame_fb);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static enum infoframe_avi_picture_aspect_ratio
> +get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> +{
> +	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> +	switch (aspect_ratio) {
> +	case DRM_MODE_PICTURE_ASPECT_4_3:
> +		return INFOFRAME_AVI_PIC_AR_4_3;
> +	case DRM_MODE_PICTURE_ASPECT_16_9:
> +		return INFOFRAME_AVI_PIC_AR_16_9;
> +	default:
> +		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> +	}
> +}
> +
> +static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> +				 drmModeModeInfo *drm_mode)
> +{
> +	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> +
> +	return vic_mode->hactive == drm_mode->hdisplay &&
> +	       vic_mode->vactive == drm_mode->vdisplay &&
> +	       vic_mode->vrefresh == drm_mode->vrefresh &&
> +	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> +}
> +
> +static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
> +				   uint32_t height, uint32_t format,
> +				   uint64_t modifier, size_t *stride)
> +{
> +	size_t stride_min;
> +	uint32_t max_tile_w = 4, tile_w, tile_h;
> +	int i;
> +	struct igt_fb dummy;
> +
> +	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> +
> +	/* Randomize the stride to less than twice the minimum. */
> +	*stride = (rand() % stride_min) + stride_min;
> +
> +	/*
> +	 * Create a dummy FB to determine bpp for each plane, and calculate
> +	 * the maximum tile width from that.
> +	 */
> +	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> +	for (i = 0; i < dummy.num_planes; i++) {
> +		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
> +				     &tile_w, &tile_h);
> +
> +		if (tile_w > max_tile_w)
> +			max_tile_w = tile_w;
> +	}
> +	igt_remove_fb(data->drm_fd, &dummy);
> +
> +	/*
> +	 * Pixman requires the stride to be aligned to 32-bits, which is
> +	 * reflected in the initial value of max_tile_w and the hw
> +	 * may require a multiple of tile width, choose biggest of the 2.
> +	 */
> +	*stride = ALIGN(*stride, max_tile_w);
> +}
> +
> +static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> +				  uint32_t height, uint32_t format,
> +				  uint64_t *modifier)
> +{
> +	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> +		/* Randomize the column height to less than twice the minimum.
> +		 */
> +		size_t column_height = (rand() % height) + height;
> +
> +		igt_debug(
> +			"Selecting VC4 SAND256 tiling with column height %ld\n",
> +			column_height);
> +
> +		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
> +			column_height);
> +	}
> +}
> +
> +static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
> +				  drmModeModeInfo *mode, uint32_t *width,
> +				  uint32_t *height, uint32_t *format,
> +				  uint64_t *modifier, bool allow_yuv)
> +{
> +	int min_dim;
> +	uint32_t idx[plane->format_mod_count];
> +	unsigned int count = 0;
> +	unsigned int i;
> +
> +	/* First pass to count the supported formats. */
> +	for (i = 0; i < plane->format_mod_count; i++)
> +		if (igt_fb_supported_format(plane->formats[i]) &&
> +		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> +			idx[count++] = i;
> +
> +	igt_assert(count > 0);
> +
> +	i = idx[rand() % count];
> +	*format = plane->formats[i];
> +	*modifier = plane->modifiers[i];
> +
> +	update_tiled_modifier(plane, *width, *height, *format, modifier);
> +
> +	/*
> +	 * Randomize width and height in the mode dimensions range.
> +	 *
> +	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> +	 * least min_dim, because src_w = width - (rand % w / 2).
> +	 *
> +	 * Use a minimum dimension of 16 for YUV, because planar YUV
> +	 * subsamples the UV plane.
> +	 */
> +	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> +
> +	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> +	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> +}
> +
> +static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> +			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> +			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> +			    struct igt_fb *fb)
> +{
> +	igt_plane_set_fb(plane, fb);
> +
> +	igt_plane_set_position(plane, crtc_x, crtc_y);
> +	igt_plane_set_size(plane, crtc_w, crtc_h);
> +
> +	igt_fb_set_position(fb, plane, src_x, src_y);
> +	igt_fb_set_size(fb, plane, src_w, src_h);
> +}
> +
> +static void randomize_plane_coordinates(
> +	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
> +	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
> +	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
> +	int32_t *crtc_y, bool allow_scaling)
> +{
> +	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> +	uint32_t width = fb->width, height = fb->height;
> +	double ratio;
> +	int ret;
> +
> +	/* Randomize source offset in the first half of the original size. */
> +	*src_x = rand() % (width / 2);
> +	*src_y = rand() % (height / 2);
> +
> +	/* The source size only includes the active source area. */
> +	*src_w = width - *src_x;
> +	*src_h = height - *src_y;
> +
> +	if (allow_scaling) {
> +		*crtc_w = (rand() % mode->hdisplay) + 1;
> +		*crtc_h = (rand() % mode->vdisplay) + 1;
> +
> +		/*
> +		 * Don't bother with scaling if dimensions are quite close in
> +		 * order to get non-scaling cases more frequently. Also limit
> +		 * scaling to 3x to avoid aggressive filtering that makes
> +		 * comparison less reliable, and don't go above 2x downsampling
> +		 * to avoid possible hw limitations.
> +		 */
> +
> +		ratio = ((double)*crtc_w / *src_w);
> +		if (ratio < 0.5)
> +			*src_w = *crtc_w * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_w = *src_w;
> +		else if (ratio > 3.0)
> +			*crtc_w = *src_w * 3;
> +
> +		ratio = ((double)*crtc_h / *src_h);
> +		if (ratio < 0.5)
> +			*src_h = *crtc_h * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_h = *src_h;
> +		else if (ratio > 3.0)
> +			*crtc_h = *src_h * 3;
> +	} else {
> +		*crtc_w = *src_w;
> +		*crtc_h = *src_h;
> +	}
> +
> +	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> +		/*
> +		 * When scaling is involved, make sure to not go off-bounds or
> +		 * scaled clipping may result in decimal dimensions, that most
> +		 * drivers don't support.
> +		 */
> +		if (*crtc_w < mode->hdisplay)
> +			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> +		else
> +			*crtc_x = 0;
> +
> +		if (*crtc_h < mode->vdisplay)
> +			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> +		else
> +			*crtc_y = 0;
> +	} else {
> +		/*
> +		 * Randomize the on-crtc position and allow the plane to go
> +		 * off-display by less than half of its on-crtc dimensions.
> +		 */
> +		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> +		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> +	}
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	ret = igt_display_try_commit_atomic(
> +		&data->display,
> +		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
> +		NULL);
> +	if (!ret)
> +		return;
> +
> +	/* Coordinates are logged in the dumped debug log, so only report w/h on
> +	 * failure here. */
> +	igt_assert_f(ret != -ENOSPC,
> +		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
> +		     width, height);
> +
> +	/* Make YUV coordinates a multiple of 2 and retry the math. */
> +	if (is_yuv) {
> +		*src_x &= ~1;
> +		*src_y &= ~1;
> +		*src_w &= ~1;
> +		*src_h &= ~1;
> +		/* To handle 1:1 scaling, clear crtc_w/h too. */
> +		*crtc_w &= ~1;
> +		*crtc_h &= ~1;
> +
> +		if (*crtc_x < 0 && (*crtc_x & 1))
> +			(*crtc_x)++;
> +		else
> +			*crtc_x &= ~1;
> +
> +		/* If negative, round up to 0 instead of down */
> +		if (*crtc_y < 0 && (*crtc_y & 1))
> +			(*crtc_y)++;
> +		else
> +			*crtc_y &= ~1;
> +
> +		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> +				*crtc_h, *crtc_x, *crtc_y, fb);
> +		ret = igt_display_try_commit_atomic(
> +			&data->display,
> +			DRM_MODE_ATOMIC_TEST_ONLY |
> +				DRM_MODE_ATOMIC_ALLOW_MODESET,
> +			NULL);
> +		if (!ret)
> +			return;
> +	}
> +
> +	igt_assert(!ret || allow_scaling);
> +	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> +		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
> +
> +	*crtc_w = *src_w;
> +	*crtc_h = *src_h;
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	igt_display_commit_atomic(&data->display,
> +				  DRM_MODE_ATOMIC_TEST_ONLY |
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET,
> +				  NULL);
> +}
> +
> +static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
> +			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
> +			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
> +			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
> +{
> +	cairo_surface_t *surface;
> +	cairo_surface_t *clipped_surface;
> +	cairo_t *cr;
> +
> +	surface = igt_get_cairo_surface(data->drm_fd, fb);
> +
> +	if (src_x || src_y) {
> +		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> +							     src_w, src_h);
> +
> +		cr = cairo_create(clipped_surface);
> +
> +		cairo_translate(cr, -1. * src_x, -1. * src_y);
> +
> +		cairo_set_source_surface(cr, surface, 0, 0);
> +
> +		cairo_paint(cr);
> +		cairo_surface_flush(clipped_surface);
> +
> +		cairo_destroy(cr);
> +	} else {
> +		clipped_surface = surface;
> +	}
> +
> +	cr = cairo_create(result);
> +
> +	cairo_translate(cr, crtc_x, crtc_y);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
> +	}
> +
> +	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> +	cairo_surface_destroy(clipped_surface);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_pattern_set_filter(cairo_get_source(cr),
> +					 CAIRO_FILTER_BILINEAR);
> +		cairo_pattern_set_extend(cairo_get_source(cr),
> +					 CAIRO_EXTEND_NONE);
> +	}
> +
> +	cairo_paint(cr);
> +	cairo_surface_flush(result);
> +
> +	cairo_destroy(cr);
> +}
> +
> +static void prepare_randomized_plane(chamelium_data_t *data,
> +				     drmModeModeInfo *mode, igt_plane_t *plane,
> +				     struct igt_fb *overlay_fb,
> +				     unsigned int index,
> +				     cairo_surface_t *result_surface,
> +				     bool allow_scaling, bool allow_yuv)
> +{
> +	struct igt_fb pattern_fb;
> +	uint32_t overlay_fb_w, overlay_fb_h;
> +	uint32_t overlay_src_w, overlay_src_h;
> +	uint32_t overlay_src_x, overlay_src_y;
> +	int32_t overlay_crtc_x, overlay_crtc_y;
> +	uint32_t overlay_crtc_w, overlay_crtc_h;
> +	uint32_t format;
> +	uint64_t modifier;
> +	size_t stride;
> +	bool tiled;
> +	int fb_id;
> +
> +	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> +			      &format, &modifier, allow_yuv);
> +
> +	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> +	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
> +		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
> +		  tiled ? "tiled" : "linear");
> +
> +	/* Get a pattern framebuffer for the overlay plane. */
> +	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> +					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
> +			       modifier, &stride);
> +
> +	igt_debug("Plane %d: stride %ld\n", index, stride);
> +
> +	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> +					   modifier, stride);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> +				    &overlay_src_w, &overlay_src_h,
> +				    &overlay_src_x, &overlay_src_y,
> +				    &overlay_crtc_w, &overlay_crtc_h,
> +				    &overlay_crtc_x, &overlay_crtc_y,
> +				    allow_scaling);
> +
> +	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
> +		  overlay_src_h);
> +	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> +		  overlay_src_x, overlay_src_y);
> +	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
> +		  overlay_crtc_h);
> +	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
> +		  overlay_crtc_y);
> +
> +	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> +			 overlay_src_x, overlay_src_y, overlay_crtc_w,
> +			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
> +			 &pattern_fb);
> +
> +	/* Remove the original pattern framebuffer. */
> +	igt_remove_fb(data->drm_fd, &pattern_fb);
> +}
> +
> +static const char test_display_one_mode_desc[] =
> +	"Pick the first mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_one_mode(chamelium_data_t *data,
> +				  struct chamelium_port *port, uint32_t fourcc,
> +				  enum chamelium_check check, int count)
> +{
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	igt_require(igt_plane_has_format_mod(primary, fourcc,
> +					     DRM_FORMAT_MOD_LINEAR));
> +
> +	mode = &connector->modes[0];
> +	if (check == CHAMELIUM_CHECK_ANALOG) {
> +		bool bridge = chamelium_check_analog_bridge(data, port);
> +
> +		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> +	}
> +
> +	do_test_display(data, port, output, mode, fourcc, check, count);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_all_modes_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_all_modes(chamelium_data_t *data,
> +				   struct chamelium_port *port, uint32_t fourcc,
> +				   enum chamelium_check check, int count)
> +{
> +	bool bridge;
> +	int i, count_modes;
> +
> +	if (check == CHAMELIUM_CHECK_ANALOG)
> +		bridge = chamelium_check_analog_bridge(data, port);
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +		igt_require(igt_plane_has_format_mod(primary, fourcc,
> +						     DRM_FORMAT_MOD_LINEAR));
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> +		    prune_vga_mode(data, mode))
> +			continue;
> +
> +		do_test_display(data, port, output, mode, fourcc, check, count);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_frame_dump_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then download the captured frames and compare them "
> +	"bit-by-bit to the sent ones";
> +static void test_display_frame_dump(chamelium_data_t *data,
> +				    struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		struct igt_fb fb;
> +		struct chamelium_frame_dump *frame;
> +		drmModeModeInfo *mode;
> +		drmModeConnector *connector;
> +		int fb_id, j;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		igt_debug("Reading frame dumps from Chamelium...\n");
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> +		for (j = 0; j < 5; j++) {
> +			frame = chamelium_read_captured_frame(data->chamelium,
> +							      j);
> +			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> +			chamelium_destroy_frame_dump(frame);
> +		}
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_aspect_ratio_desc[] =
> +	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> +	"check they include the relevant fields";
> +static void test_display_aspect_ratio(chamelium_data_t *data,
> +				      struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	int fb_id, i;
> +	struct igt_fb fb;
> +	bool found, ok;
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_avi infoframe_avi;
> +	uint8_t vic = 16; /* TODO: test more VICs */
> +	const struct vic_mode *vic_mode;
> +	uint32_t aspect_ratio;
> +	enum infoframe_avi_picture_aspect_ratio frame_ar;
> +
> +	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port,
> +					  IGT_CUSTOM_EDID_ASPECT_RATIO);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	vic_mode = &vic_modes[vic];
> +	aspect_ratio = vic_mode->picture_ar;
> +
> +	found = false;
> +	igt_assert(connector->count_modes > 0);
> +	for (i = 0; i < connector->count_modes; i++) {
> +		mode = &connector->modes[i];
> +
> +		if (vic_mode_matches_drm(vic_mode, mode)) {
> +			found = true;
> +			break;
> +		}
> +	}
> +	igt_assert_f(found,
> +		     "Failed to find mode with the correct aspect ratio\n");
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> +						 CHAMELIUM_INFOFRAME_AVI);
> +	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> +
> +	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> +				 infoframe->payload, infoframe->payload_size);
> +	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> +
> +	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> +
> +	igt_debug("Checking AVI InfoFrame\n");
> +	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> +		  infoframe_avi.picture_aspect_ratio, frame_ar);
> +	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> +		  infoframe_avi.vic, vic);
> +
> +	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> +	igt_assert(infoframe_avi.vic == vic);
> +
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_remove_fb(data->drm_fd, &fb);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_planes_random_desc[] =
> +	"Setup a few overlay planes with random parameters, capture the frame "
> +	"and check it matches the expected output";
> +static void test_display_planes_random(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum chamelium_check check)
> +{
> +	igt_output_t *output;
> +	drmModeModeInfo *mode;
> +	igt_plane_t *primary_plane;
> +	struct igt_fb primary_fb;
> +	struct igt_fb result_fb;
> +	struct igt_fb *overlay_fbs;
> +	igt_crc_t *crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	unsigned int overlay_planes_max = 0;
> +	unsigned int overlay_planes_count;
> +	cairo_surface_t *result_surface;
> +	int captured_frame_count;
> +	bool allow_scaling;
> +	bool allow_yuv;
> +	unsigned int i;
> +	unsigned int fb_id;
> +
> +	switch (check) {
> +	case CHAMELIUM_CHECK_CRC:
> +		allow_scaling = false;
> +		allow_yuv = false;
> +		break;
> +	case CHAMELIUM_CHECK_CHECKERBOARD:
> +		allow_scaling = true;
> +		allow_yuv = true;
> +		break;
> +	default:
> +		igt_assert(false);
> +	}
> +
> +	srand(time(NULL));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Find the connector and pipe. */
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +
> +	mode = igt_output_get_mode(output);
> +
> +	/* Get a framebuffer for the primary plane. */
> +	primary_plane =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary_plane);
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> +	igt_assert(fb_id > 0);
> +
> +	/* Get a framebuffer for the cairo composition result. */
> +	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
> +			      &result_fb);
> +	igt_assert(fb_id > 0);
> +
> +	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> +
> +	/* Paint the primary framebuffer on the result surface. */
> +	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> +			 &primary_fb);
> +
> +	/* Configure the primary plane. */
> +	igt_plane_set_fb(primary_plane, &primary_fb);
> +
> +	overlay_planes_max =
> +		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> +
> +	/* Limit the number of planes to a reasonable scene. */
> +	overlay_planes_max = min(overlay_planes_max, 4u);
> +
> +	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> +	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> +
> +	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> +
> +	for (i = 0; i < overlay_planes_count; i++) {
> +		struct igt_fb *overlay_fb = &overlay_fbs[i];
> +		igt_plane_t *plane = igt_output_get_plane_type_index(
> +			output, DRM_PLANE_TYPE_OVERLAY, i);
> +		igt_assert(plane);
> +
> +		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> +					 result_surface, allow_scaling,
> +					 allow_yuv);
> +	}
> +
> +	cairo_surface_destroy(result_surface);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&result_fb);
> +
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == 1);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
> +						crc, &result_fb, 0);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &result_fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	for (i = 0; i < overlay_planes_count; i++)
> +		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> +
> +	free(overlay_fbs);
> +
> +	igt_remove_fb(data->drm_fd, &primary_fb);
> +	igt_remove_fb(data->drm_fd, &result_fb);
> +}
> +
> +IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-single", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("dp-crc-fast", DisplayPort)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-multiple", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("dp-frame-dump", DisplayPort)
> +			test_display_frame_dump(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-single", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("hdmi-crc-fast", HDMIA)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-multiple", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CRC, 1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-crc-planes-random", HDMIA)
> +			test_display_planes_random(&data, port,
> +						   CHAMELIUM_CHECK_CRC);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (!igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CHECKERBOARD,
> +						1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> +			test_display_planes_random(
> +				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("hdmi-frame-dump", HDMIA)
> +			test_display_frame_dump(&data, port);
> +
> +		igt_describe(test_display_aspect_ratio_desc);
> +		connector_subtest("hdmi-aspect-ratio", HDMIA)
> +			test_display_aspect_ratio(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("vga-frame-dump", VGA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_ANALOG, 1);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
> new file mode 100644
> index 00000000..b9544288
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.c
> @@ -0,0 +1,330 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +
> +void chamelium_init_test(chamelium_data_t *data)
> +{
> +	int i;
> +
> +	/* So fbcon doesn't try to reprobe things itself */
> +	kmstest_set_vt_graphics_mode();
> +
> +	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
> +	igt_display_require(&data->display, data->drm_fd);
> +	igt_require(data->display.is_atomic);
> +
> +	/*
> +	 * XXX: disabling modeset, can be removed when
> +	 * igt_display_require will start doing this for us
> +	 */
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	/* we need to initalize chamelium after igt_display_require */
> +	data->chamelium = chamelium_init(data->drm_fd, &data->display);
> +	igt_require(data->chamelium);
> +
> +	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
> +
> +	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> +		data->edids[i] = chamelium_new_edid(data->chamelium,
> +						    igt_kms_get_custom_edid(i));
> +	}
> +}
> +
> +/* Wait for hotplug and return the remaining time left from timeout */
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> +{
> +	struct timespec start, end;
> +	int elapsed;
> +	bool detected;
> +
> +	igt_assert_eq(igt_gettime(&start), 0);
> +	detected = igt_hotplug_detected(mon, *timeout);
> +	igt_assert_eq(igt_gettime(&end), 0);
> +
> +	elapsed = igt_time_elapsed(&start, &end);
> +	igt_assert_lte(0, elapsed);
> +	*timeout = max(0, *timeout - elapsed);
> +
> +	return detected;
> +}
> +
> +/**
> + * chamelium_wait_for_connector_after_hotplug:
> + *
> + * Waits for the connector attached to @port to have a status of @status after
> + * it's plugged/unplugged.
> + *
> + */
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status)
> +{
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int hotplug_count = 0;
> +
> +	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> +		  chamelium_port_get_name(port),
> +		  kmstest_connector_status_str(status));
> +
> +	while (timeout > 0) {
> +		if (!chamelium_wait_for_hotplug(mon, &timeout))
> +			break;
> +
> +		hotplug_count++;
> +
> +		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> +						port) == status)
> +			return;
> +	}
> +
> +	igt_assert_f(
> +		false,
> +		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> +		chamelium_port_get_name(port),
> +		kmstest_connector_status_str(status),
> +		kmstest_connector_status_str(chamelium_reprobe_connector(
> +			&data->display, data->chamelium, port)),
> +		hotplug_count);
> +}
> +
> +/**
> + * chamelium_port_get_connector:
> + * @data: The Chamelium data instance to use
> + * @port: The chamelium port to prepare its connector
> + * @edid: The chamelium's default EDID has a lot of resolutions, way more then
> + * 		  we need to test. Additionally the default EDID doesn't support
> + *        HDMI audio.
> + *
> + * Makes sure the output display of the connector attached to @port is connected
> + * and ready for use.
> + *
> + * Returns: a pointer to the enabled igt_output_t
> + */
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid)
> +{
> +	igt_display_t *display = &data->display;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	/* The chamelium's default EDID has a lot of resolutions, way more then
> +	 * we need to test. Additionally the default EDID doesn't support HDMI
> +	 * audio.
> +	 */
> +	chamelium_set_edid(data, port, edid);
> +
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_display_reset(display);
> +
> +	output = chamelium_get_output_for_port(data, port);
> +
> +	/* Refresh pipe to update connected status */
> +	igt_output_set_pipe(output, PIPE_NONE);
> +
> +	pipe = chamelium_get_pipe_for_output(display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	return output;
> +}
> +
> +/**
> + * chamelium_enable_output:
> + *
> + * Modesets the connector attached to @port for the assigned @mode and draws the
> + * @fb.
> + *
> + */
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb)
> +{
> +	igt_display_t *display = output->display;
> +	igt_plane_t *primary =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +
> +	igt_assert(primary);
> +
> +	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> +	igt_plane_set_fb(primary, fb);
> +	igt_output_override_mode(output, mode);
> +
> +	/* Clear any color correction values that might be enabled */
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_GAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
> +					       NULL, 0);
> +
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> +		usleep(250000);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +/* Return pipe attached to @outpu.t */
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output)
> +{
> +	enum pipe pipe;
> +
> +	for_each_pipe(display, pipe) {
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			return pipe;
> +		}
> +	}
> +
> +	igt_assert_f(false, "No pipe found for output %s\n",
> +		     igt_output_name(output));
> +}
> +
> +static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
> +					 size_t height, size_t stride,
> +					 size_t block_size)
> +{
> +	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
> +			      0xffffffff };
> +	unsigned i, j;
> +
> +	for (i = 0; i < height; i++)
> +		for (j = 0; j < width; j++)
> +			*(data + i * stride / 4 +
> +			  j) = colors[((j / block_size) + (i / block_size)) % 5];
> +}
> +
> +/**
> + * chamelium_get_pattern_fb:
> + *
> + * Creates an @fb with an xr24 pattern and returns the fb_id.
> + *
> + */
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb)
> +{
> +	int fb_id;
> +	void *ptr;
> +
> +	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> +
> +	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> +			      DRM_FORMAT_MOD_LINEAR, fb);
> +	igt_assert(fb_id > 0);
> +
> +	ptr = igt_fb_map_buffer(fb->fd, fb);
> +	igt_assert(ptr);
> +
> +	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> +				     block_size);
> +	igt_fb_unmap_buffer(fb, ptr);
> +
> +	return fb_id;
> +}
> +
> +/* Generate a simple @fb for the size of @mode. */
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode)
> +{
> +	int fb_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, fb);
> +
> +	igt_assert(fb_id > 0);
> +}
> +
> +/* Returns the first preferred mode for the connector attached to @port. */
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(chamelium, port, false);
> +	drmModeModeInfo mode;
> +	igt_assert(&connector->modes[0] != NULL);
> +	memcpy(&mode, &connector->modes[0], sizeof(mode));
> +	drmModeFreeConnector(connector);
> +	return mode;
> +}
> +
> +/* Returns the igt display output for the connector attached to @port. */
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_output_t *output =
> +		igt_output_from_connector(&data->display, connector);
> +	drmModeFreeConnector(connector);
> +	igt_assert(output != NULL);
> +	return output;
> +}
> +
> +/* Set the EDID of index @edid to Chamelium's @port. */
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid)
> +{
> +	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> +}
> +
> +/**
> + * chamelium_check_analog_bridge:
> + *
> + * Check if the connector associalted to @port is an analog bridge by checking
> + * if it has its own EDID.
> + *
> + */
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +	uint64_t edid_blob_id;
> +	const struct edid *edid;
> +	char edid_vendor[3];
> +
> +	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> +		drmModeFreeConnector(connector);
> +		return false;
> +	}
> +
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob =
> +			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
> +
> +	edid = (const struct edid *)edid_blob->data;
> +	edid_get_mfg(edid, edid_vendor);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +
> +	/* Analog bridges provide their own EDID */
> +	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> +	    edid_vendor[2] != 'T')
> +		return true;
> +
> +	return false;
> +}
> \ No newline at end of file
> diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
> new file mode 100644
> index 00000000..09fa4829
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +
> +#include "igt.h"
> +
> +#define ONLINE_TIMEOUT 20 /* seconds */
> +
> +#define for_each_port(p, port)                                 \
> +	for (p = 0, port = data.ports[p]; p < data.port_count; \
> +	     p++, port = data.ports[p])
> +
> +#define connector_subtest(name__, type__)                           \
> +	igt_subtest(name__)                                         \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +/*
> + * The chamelium data structure is used to store all the information known about
> + * chamelium to run the tests.
> + */
> +typedef struct {
> +	struct chamelium *chamelium;
> +	struct chamelium_port **ports;
> +	igt_display_t display;
> +	int port_count;
> +
> +	int drm_fd;
> +
> +	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> +} chamelium_data_t;
> +
> +void chamelium_init_test(chamelium_data_t *data);
> +
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status);
> +
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid);
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb);
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output);
> +
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb);
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode);
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port);
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port);
> +
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid);
> +
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port);
> +
> +#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
> diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
> new file mode 100644
> index 00000000..8a4e1aba
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_hpd.c
> @@ -0,0 +1,512 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the HPD functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "kms_chamelium_helper.h"
> +
> +#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> +#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> +
> +#define HPD_TOGGLE_COUNT_VGA 5
> +#define HPD_TOGGLE_COUNT_DP_HDMI 15
> +#define HPD_TOGGLE_COUNT_FAST 3
> +
> +enum test_modeset_mode {
> +	TEST_MODESET_ON,
> +	TEST_MODESET_ON_OFF,
> +	TEST_MODESET_OFF,
> +};
> +
> +static void try_suspend_resume_hpd(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   enum igt_suspend_state state,
> +				   enum igt_suspend_test test,
> +				   struct udev_monitor *mon, bool connected)
> +{
> +	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> +						     DRM_MODE_CONNECTED;
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int delay;
> +	int p;
> +
> +	igt_flush_uevents(mon);
> +
> +	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> +
> +	if (port) {
> +		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> +					      !connected);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			port = data->ports[p];
> +			chamelium_schedule_hpd_toggle(data->chamelium, port,
> +						      delay, !connected);
> +		}
> +
> +		port = NULL;
> +	}
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	if (port) {
> +		igt_assert_eq(chamelium_reprobe_connector(
> +				      &data->display, data->chamelium, port),
> +			      target_state);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			drmModeConnection current_state;
> +
> +			port = data->ports[p];
> +			/*
> +			 * There could be as many hotplug events sent by
> +			 * driver as connectors we scheduled an HPD toggle on
> +			 * above, depending on timing. So if we're not seeing
> +			 * the expected connector state try to wait for an HPD
> +			 * event for each connector/port.
> +			 */
> +			current_state = chamelium_reprobe_connector(
> +				&data->display, data->chamelium, port);
> +			if (p > 0 && current_state != target_state) {
> +				igt_assert(chamelium_wait_for_hotplug(
> +					mon, &timeout));
> +				current_state = chamelium_reprobe_connector(
> +					&data->display, data->chamelium, port);
> +			}
> +
> +			igt_assert_eq(current_state, target_state);
> +		}
> +
> +		port = NULL;
> +	}
> +}
> +
> +static const char test_basic_hotplug_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug";
> +static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
> +			 int toggle_count, enum test_modeset_mode modeset_mode)
> +{
> +	int i;
> +	enum pipe pipe;
> +	struct igt_fb fb = { 0 };
> +	drmModeModeInfo mode;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	igt_output_t *output = chamelium_get_output_for_port(data, port);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +
> +	for (i = 0; i < toggle_count; i++) {
> +		igt_flush_uevents(mon);
> +
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF ||
> +		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
> +			if (i == 0) {
> +				/* We can only get mode and pipe once we are
> +				 * connected */
> +				output = chamelium_get_output_for_port(data,
> +								       port);
> +				pipe = chamelium_get_pipe_for_output(
> +					&data->display, output);
> +				mode = chamelium_get_mode_for_port(
> +					data->chamelium, port);
> +				chamelium_create_fb_for_mode(data, &fb, &mode);
> +			}
> +
> +			igt_output_set_pipe(output, pipe);
> +			chamelium_enable_output(data, port, output, &mode, &fb);
> +		}
> +
> +		/* Now check if we get a hotplug from disconnection */
> +		chamelium_unplug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF) {
> +			igt_output_set_pipe(output, PIPE_NONE);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static const char test_hotplug_for_each_pipe_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug for each pipe with valid output";
> +static void test_hotplug_for_each_pipe(chamelium_data_t *data,
> +				       struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	enum pipe pipe;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	/* Disconnect if any port got connected */
> +	chamelium_unplug(data->chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_DISCONNECTED);
> +
> +	for_each_pipe(&data->display, pipe) {
> +		igt_flush_uevents(mon);
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +		output = chamelium_get_output_for_port(data, port);
> +
> +		/* If pipe is valid for output then set it */
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			igt_output_set_pipe(output, pipe);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +
> +		chamelium_unplug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +		igt_flush_uevents(mon);
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_suspend_resume_hpd_desc[] =
> +	"Toggle HPD during suspend, check that uevents are sent and connector "
> +	"status is updated";
> +static void test_suspend_resume_hpd(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_suspend_state state,
> +				    enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_suspend_resume_hpd_common_desc[] =
> +	"Toggle HPD during suspend on all connectors, check that uevents are "
> +	"sent and connector status is updated";
> +static void test_suspend_resume_hpd_common(chamelium_data_t *data,
> +					   enum igt_suspend_state state,
> +					   enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	struct chamelium_port *port;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		port = data->ports[p];
> +		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_without_ddc_desc[] =
> +	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> +static void test_hpd_without_ddc(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +	igt_flush_uevents(mon);
> +
> +	/* Disable the DDC on the connector and make sure we still get a
> +	 * hotplug
> +	 */
> +	chamelium_port_set_ddc_state(data->chamelium, port, false);
> +	chamelium_plug(data->chamelium, port);
> +
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> +						  data->chamelium, port),
> +		      DRM_MODE_CONNECTED);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_storm_detect_desc[] =
> +	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> +	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> +	"storm";
> +static void test_hpd_storm_detect(chamelium_data_t *data,
> +				  struct chamelium_port *port, int width)
> +{
> +	struct udev_monitor *mon;
> +	int count = 0;
> +
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> +
> +	mon = igt_watch_uevents();
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +
> +	/*
> +	 * Polling should have been enabled by the HPD storm at this point,
> +	 * so we should only get at most 1 hotplug event
> +	 */
> +	igt_until_timeout(5)
> +		count += igt_hotplug_detected(mon, 1);
> +	igt_assert_lt(count, 2);
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_hpd_storm_disable_desc[] =
> +	"Disable HPD storm detection, trigger a storm and check the kernel "
> +	"doesn't detect one";
> +static void test_hpd_storm_disable(chamelium_data_t *data,
> +				   struct chamelium_port *port, int width)
> +{
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> +
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("dp-hpd-storm", DisplayPort)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_DP);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_DP);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("hdmi-hpd-storm", HDMIA)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_HDMI);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_HDMI);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-suspend", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-hibernate", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_without_ddc_desc);
> +		connector_subtest("vga-hpd-without-ddc", VGA)
> +			test_hpd_without_ddc(&data, port);
> +	}
> +
> +	igt_describe("Tests that operate on all connectors");
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(data.port_count);
> +		}
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-suspend")
> +			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
> +						       SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-hibernate")
> +			test_suspend_resume_hpd_common(&data,
> +						       SUSPEND_STATE_DISK,
> +						       SUSPEND_TEST_DEVICES);
> +	}
> +
> +	igt_describe(test_hotplug_for_each_pipe_desc);
> +	connector_subtest("vga-hpd-for-each-pipe", VGA)
> +		test_hotplug_for_each_pipe(&data, port);
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
> index 0d307730..6e5cc436 100644
> --- a/tests/intel-ci/blacklist.txt
> +++ b/tests/intel-ci/blacklist.txt
> @@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
>  # is too costly in comparison to the value
>  # provided.
>  ###############################################
> -igt@kms_chamelium@hdmi-.*-planes-random
> +igt@kms_chamelium_frames@hdmi-.*-planes-random
>  ###############################################
>  # Broadcom
>  ###############################################
> diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
> index f57f8ff3..fb4c0f73 100644
> --- a/tests/intel-ci/fast-feedback.testlist
> +++ b/tests/intel-ci/fast-feedback.testlist
> @@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
>  igt@kms_addfb_basic@unused-offsets
>  igt@kms_addfb_basic@unused-pitches
>  igt@kms_busy@basic
> -igt@kms_chamelium@dp-hpd-fast
> -igt@kms_chamelium@dp-edid-read
> -igt@kms_chamelium@dp-crc-fast
> -igt@kms_chamelium@hdmi-hpd-fast
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@vga-hpd-fast
> -igt@kms_chamelium@vga-edid-read
> +igt@kms_chamelium_hpd@dp-hpd-fast
> +igt@kms_chamelium_edid@dp-edid-read
> +igt@kms_chamelium_frames@dp-crc-fast
> +igt@kms_chamelium_hpd@hdmi-hpd-fast
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_hpd@vga-hpd-fast
> +igt@kms_chamelium_edid@vga-edid-read
>  igt@kms_prop_blob@basic
>  igt@kms_cursor_legacy@basic-busy-flip-before-cursor
>  igt@kms_cursor_legacy@basic-flip-after-cursor
> @@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
>  igt@i915_suspend@basic-s3-without-i915
>  igt@gem_exec_suspend@basic-s0
>  igt@gem_exec_suspend@basic-s3
> -igt@kms_chamelium@common-hpd-after-suspend
> +igt@kms_chamelium_hpd@common-hpd-after-suspend
>  igt@kms_pipe_crc_basic@suspend-read-crc
> diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
> index f0ae30e3..f9242232 100644
> --- a/tests/kms_color_helper.h
> +++ b/tests/kms_color_helper.h
> @@ -27,7 +27,7 @@
>  
>  /*
>   * This header is for code that is shared between kms_color.c and
> - * kms_color_chamelium.c. Reusability elsewhere can be questionable.
> + * kms_chamelium_color.c. Reusability elsewhere can be questionable.
>   */
>  
>  #include <math.h>
> diff --git a/tests/meson.build b/tests/meson.build
> index 5c052e73..b52399d5 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -260,7 +260,10 @@ msm_progs = [
>  ]
>  
>  chamelium_progs = [
> -	'kms_chamelium',
> +	'kms_chamelium_audio',
> +	'kms_chamelium_edid',
> +	'kms_chamelium_frames',
> +	'kms_chamelium_hpd',
>  ]
>  
>  test_deps = [ igt_deps ]
> @@ -309,7 +312,8 @@ endforeach
>  if chamelium.found()
>  	foreach prog : chamelium_progs
>  		test_executables += executable(prog,
> -				 join_paths('chamelium', prog + '.c'),
> +				 [join_paths('chamelium', prog + '.c'), 
> +				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
>  				 dependencies : test_deps,
>  				 install_dir : libexecdir,
>  				 install_rpath : libexecdir_rpathdir,
> @@ -436,13 +440,13 @@ test_executables += executable('kms_color',
>  test_list += 'kms_color'
>  
>  if chamelium.found()
> -       test_executables += executable('kms_color_chamelium',
> -                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
> +       test_executables += executable('kms_chamelium_color',
> +                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
>                               dependencies : test_deps + [ chamelium ],
>                               install_dir : libexecdir,
>                               install_rpath : libexecdir_rpathdir,
>                               install : true)
> -       test_list += 'kms_color_chamelium'
> +       test_list += 'kms_chamelium_color'
>  endif
>  
>  test_executables += executable('sw_sync', 'sw_sync.c',
> diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
> index dd45d12a..a5521021 100644
> --- a/tests/vc4_ci/vc4-chamelium-fast.testlist
> +++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
> @@ -1,14 +1,14 @@
> -igt@kms_chamelium@hdmi-crc-abgr8888
> -igt@kms_chamelium@hdmi-crc-argb1555
> -igt@kms_chamelium@hdmi-crc-argb8888
> -igt@kms_chamelium@hdmi-crc-bgr565
> -igt@kms_chamelium@hdmi-crc-bgr888
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@hdmi-crc-rgb565
> -igt@kms_chamelium@hdmi-crc-rgb888
> -igt@kms_chamelium@hdmi-crc-xbgr8888
> -igt@kms_chamelium@hdmi-crc-xrgb1555
> -igt@kms_chamelium@hdmi-crc-xrgb8888
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-hpd
> -igt@kms_chamelium@hdmi-hpd-fast
> +igt@kms_chamelium_frames@hdmi-crc-abgr8888
> +igt@kms_chamelium_frames@hdmi-crc-argb1555
> +igt@kms_chamelium_frames@hdmi-crc-argb8888
> +igt@kms_chamelium_frames@hdmi-crc-bgr565
> +igt@kms_chamelium_frames@hdmi-crc-bgr888
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_frames@hdmi-crc-rgb565
> +igt@kms_chamelium_frames@hdmi-crc-rgb888
> +igt@kms_chamelium_frames@hdmi-crc-xbgr8888
> +igt@kms_chamelium_frames@hdmi-crc-xrgb1555
> +igt@kms_chamelium_frames@hdmi-crc-xrgb8888
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_hpd@hdmi-hpd
> +igt@kms_chamelium_hpd@hdmi-hpd-fast
> -- 
> 2.38.1.584.g0f3c55d4c2-goog
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] [PATCH v3] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-12-01 16:29 ` [igt-dev] [PATCH v2] " Mark Yacoub
  2022-12-02  9:48   ` Petri Latvala
@ 2022-12-06 18:56   ` Mark Yacoub
  2022-12-06 23:22     ` [igt-dev] [PATCH v4] " Mark Yacoub
  1 sibling, 1 reply; 25+ messages in thread
From: Mark Yacoub @ 2022-12-06 18:56 UTC (permalink / raw)
  To: igt-dev

[Why]
kms_chamelium tests file has grown so much and became a bit big to
manage.
Splitting specific tests like we do for kms_ tests into separate files
puts logically related functionalities into the same place so tests are
more clear.

[How]
Split kms_chamelium into 4 different tests, each testing something
specific. The tests are:
1. kms_chamelium_audio
2. kms_chamelium_edid
3. kms_chamelium_frames
4. kms_chamelium_hpd
5. kms_chamelium_color which used to be kms_color_chamelium but renamed
   for consistency.

All common code lives in kms_chamelium_helper and the function names
have a chamelium_ prefix.

v2: Praying that the warning is cleared by keeping things on same line.
v1: Fix typo and add missing #include

Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
---
 docs/chamelium.txt                            |    2 +-
 lib/igt_edid.h                                |    1 +
 lib/igt_eld.h                                 |    1 +
 lib/monitor_edids/monitor_edids_helper.c      |    2 +-
 tests/chamelium/kms_chamelium.c               | 3132 -----------------
 tests/chamelium/kms_chamelium_audio.c         |  858 +++++
 ...olor_chamelium.c => kms_chamelium_color.c} |    0
 tests/chamelium/kms_chamelium_edid.c          |  534 +++
 tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
 tests/chamelium/kms_chamelium_helper.c        |  330 ++
 tests/chamelium/kms_chamelium_helper.h        |   74 +
 tests/chamelium/kms_chamelium_hpd.c           |  512 +++
 tests/intel-ci/blacklist.txt                  |    2 +-
 tests/intel-ci/fast-feedback.testlist         |   18 +-
 tests/kms_color_helper.h                      |    2 +-
 tests/meson.build                             |   14 +-
 tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
 17 files changed, 3431 insertions(+), 3164 deletions(-)
 delete mode 100644 tests/chamelium/kms_chamelium.c
 create mode 100644 tests/chamelium/kms_chamelium_audio.c
 rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
 create mode 100644 tests/chamelium/kms_chamelium_edid.c
 create mode 100644 tests/chamelium/kms_chamelium_frames.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.h
 create mode 100644 tests/chamelium/kms_chamelium_hpd.c

diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index c4c22468..f82c8b0c 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -241,7 +241,7 @@ Current Support in IGT
 
 Support for the Chamelium platform in IGT is found in the following places:
 * lib/igt_chamelium.c: library with Chamelium-related helpers
-* tests/kms_chamelium.c: sub-tests using the Chamelium
+* tests/kms_chamelium_*.c: sub-tests using the Chamelium
 
 As of early April 2019, the following features are tested by IGT:
 * Pixel-by-pixel frame integrity tests for DP and HDMI
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 477f16c2..85a9ef5e 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdint.h>
+#include <stddef.h>
 
 #include <xf86drmMode.h>
 
diff --git a/lib/igt_eld.h b/lib/igt_eld.h
index 30d7012d..1a46b6d2 100644
--- a/lib/igt_eld.h
+++ b/lib/igt_eld.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stddef.h>
 
 #include "igt_edid.h"
 
diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
index 41f199bd..1cbf1c22 100644
--- a/lib/monitor_edids/monitor_edids_helper.c
+++ b/lib/monitor_edids/monitor_edids_helper.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 /*
  * A helper library for parsing and making use of real EDID data from monitors
  * and make them compatible with IGT and Chamelium.
diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
deleted file mode 100644
index 3c4b4d75..00000000
--- a/tests/chamelium/kms_chamelium.c
+++ /dev/null
@@ -1,3132 +0,0 @@
-/*
- * Copyright © 2016 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Lyude Paul <lyude@redhat.com>
- */
-
-#include "config.h"
-#include "igt.h"
-#include "igt_vc4.h"
-#include "igt_edid.h"
-#include "igt_eld.h"
-#include "igt_infoframe.h"
-#include "monitor_edids/dp_edids.h"
-#include "monitor_edids/hdmi_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,
-	TEST_MODESET_ON_OFF,
-	TEST_MODESET_OFF,
-};
-
-typedef struct {
-	struct chamelium *chamelium;
-	struct chamelium_port **ports;
-	igt_display_t display;
-	int port_count;
-
-	int drm_fd;
-
-	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
-} data_t;
-
-#define ONLINE_TIMEOUT 20 /* seconds */
-
-#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
-#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
-
-#define HPD_TOGGLE_COUNT_VGA 5
-#define HPD_TOGGLE_COUNT_DP_HDMI 15
-#define HPD_TOGGLE_COUNT_FAST 3
-
-static void
-get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
-{
-	drmModeConnector *connector;
-	uint64_t link_status;
-	drmModePropertyPtr prop;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		connector = chamelium_port_get_connector(data->chamelium,
-							 data->ports[p], false);
-
-		igt_assert(kmstest_get_property(data->drm_fd,
-						connector->connector_id,
-						DRM_MODE_OBJECT_CONNECTOR,
-						"link-status", NULL,
-						&link_status, &prop));
-
-		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
-
-		drmModeFreeProperty(prop);
-		drmModeFreeConnector(connector);
-	}
-}
-
-/* Wait for hotplug and return the remaining time left from timeout */
-static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
-{
-	struct timespec start, end;
-	int elapsed;
-	bool detected;
-
-	igt_assert_eq(igt_gettime(&start), 0);
-	detected = igt_hotplug_detected(mon, *timeout);
-	igt_assert_eq(igt_gettime(&end), 0);
-
-	elapsed = igt_time_elapsed(&start, &end);
-	igt_assert_lte(0, elapsed);
-	*timeout = max(0, *timeout - elapsed);
-
-	return detected;
-}
-
-static void
-wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
-				 struct chamelium_port *port,
-				 drmModeConnection status)
-{
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int hotplug_count = 0;
-
-	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
-			  chamelium_port_get_name(port),
-			  kmstest_connector_status_str(status));
-
-	while (timeout > 0) {
-		if (!wait_for_hotplug(mon, &timeout))
-			break;
-
-		hotplug_count++;
-
-		if (chamelium_reprobe_connector(&data->display, data->chamelium,
-						port) == status)
-			return;
-	}
-
-	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
-			    chamelium_port_get_name(port),
-			    kmstest_connector_status_str(status),
-			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
-}
-
-
-static int chamelium_vga_modes[][2] = {
-	{ 1600, 1200 },
-	{ 1920, 1200 },
-	{ 1920, 1080 },
-	{ 1680, 1050 },
-	{ 1280, 1024 },
-	{ 1280, 960 },
-	{ 1440, 900 },
-	{ 1280, 800 },
-	{ 1024, 768 },
-	{ 1360, 768 },
-	{ 1280, 720 },
-	{ 800, 600 },
-	{ 640, 480 },
-	{ -1, -1 },
-};
-
-static bool
-prune_vga_mode(data_t *data, drmModeModeInfo *mode)
-{
-	int i = 0;
-
-	while (chamelium_vga_modes[i][0] != -1) {
-		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
-		    mode->vdisplay == chamelium_vga_modes[i][1])
-			return false;
-
-		i++;
-	}
-
-	return true;
-}
-
-static bool
-check_analog_bridge(data_t *data, struct chamelium_port *port)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-	uint64_t edid_blob_id;
-	const struct edid *edid;
-	char edid_vendor[3];
-
-	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
-		drmModeFreeConnector(connector);
-		return false;
-	}
-
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	edid = (const struct edid *) edid_blob->data;
-	edid_get_mfg(edid, edid_vendor);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-
-	/* Analog bridges provide their own EDID */
-	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
-	    edid_vendor[2] != 'T')
-		return true;
-
-	return false;
-}
-
-static void chamelium_paint_xr24_pattern(uint32_t *data,
-					 size_t width, size_t height,
-					 size_t stride, size_t block_size)
-{
-	uint32_t colors[] = { 0xff000000,
-			      0xffff0000,
-			      0xff00ff00,
-			      0xff0000ff,
-			      0xffffffff };
-	unsigned i, j;
-
-	for (i = 0; i < height; i++)
-		for (j = 0; j < width; j++)
-			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
-}
-
-static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
-				    uint32_t fourcc, size_t block_size,
-				    struct igt_fb *fb)
-{
-	int fb_id;
-	void *ptr;
-
-	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
-
-	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
-			      DRM_FORMAT_MOD_LINEAR, fb);
-	igt_assert(fb_id > 0);
-
-	ptr = igt_fb_map_buffer(fb->fd, fb);
-	igt_assert(ptr);
-
-	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
-				     block_size);
-	igt_fb_unmap_buffer(fb, ptr);
-
-	return fb_id;
-}
-
-static void
-enable_output(data_t *data,
-	      struct chamelium_port *port,
-	      igt_output_t *output,
-	      drmModeModeInfo *mode,
-	      struct igt_fb *fb)
-{
-	igt_display_t *display = output->display;
-	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-
-	igt_assert(primary);
-
-	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
-	igt_plane_set_fb(primary, fb);
-	igt_output_override_mode(output, mode);
-
-	/* Clear any color correction values that might be enabled */
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
-
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
-		usleep(250000);
-
-	drmModeFreeConnector(connector);
-}
-
-static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
-{
-	enum pipe pipe;
-
-	for_each_pipe(display, pipe) {
-		if (igt_pipe_connector_valid(pipe, output)) {
-			return pipe;
-		}
-	}
-
-	igt_assert_f(false, "No pipe found for output %s\n",
-		     igt_output_name(output));
-}
-
-static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
-{
-	int fb_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, fb);
-
-	igt_assert(fb_id > 0);
-}
-
-static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
-								   port, false);
-	drmModeModeInfo mode;
-	igt_assert(&connector->modes[0] != NULL);
-	memcpy(&mode, &connector->modes[0], sizeof(mode));
-	drmModeFreeConnector(connector);
-	return mode;
-}
-
-static igt_output_t *get_output_for_port(data_t *data,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector =
-		chamelium_port_get_connector(data->chamelium, port, true);
-	igt_output_t *output = igt_output_from_connector(&data->display,
-							 connector);
-	drmModeFreeConnector(connector);
-	igt_assert(output != NULL);
-	return output;
-}
-
-static const char test_hotplug_for_each_pipe_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug for each pipe with valid output";
-static void
-test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	enum pipe pipe;
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	chamelium_reset_state(&data->display,
-			      data->chamelium,
-			      port,
-			      data->ports,
-			      data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	/* Disconnect if any port got connected */
-	chamelium_unplug(data->chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port,
-			DRM_MODE_DISCONNECTED);
-
-	for_each_pipe(&data->display, pipe) {
-		igt_flush_uevents(mon);
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-		output = get_output_for_port(data, port);
-
-		/* If pipe is valid for output then set it */
-		if (igt_pipe_connector_valid(pipe, output)) {
-			igt_output_set_pipe(output, pipe);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-
-		chamelium_unplug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_DISCONNECTED);
-		igt_flush_uevents(mon);
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_basic_hotplug_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug";
-static void
-test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
-	     enum test_modeset_mode modeset_mode)
-{
-	int i;
-	enum pipe pipe;
-	struct igt_fb fb = {0};
-	drmModeModeInfo mode;
-	struct udev_monitor *mon = igt_watch_uevents();
-	igt_output_t *output = get_output_for_port(data, port);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-
-	for (i = 0; i < toggle_count; i++) {
-		igt_flush_uevents(mon);
-
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF ||
-		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
-			if (i == 0) {
-				/* We can only get mode and pipe once we are connected */
-				output = get_output_for_port(data, port);
-				pipe = get_pipe_for_output(&data->display, output);
-				mode = get_mode_for_port(data->chamelium, port);
-				create_fb_for_mode(data, &fb, &mode);
-			}
-
-			igt_output_set_pipe(output, pipe);
-			enable_output(data, port, output, &mode, &fb);
-		}
-
-		/* Now check if we get a hotplug from disconnection */
-		chamelium_unplug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_DISCONNECTED);
-
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF) {
-			igt_output_set_pipe(output, PIPE_NONE);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static void set_edid(data_t *data, struct chamelium_port *port,
-		     enum igt_custom_edid_type edid)
-{
-	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
-}
-
-static const char igt_custom_edid_type_read_desc[] =
-	"Make sure the EDID exposed by KMS is the same as the screen's";
-static void
-igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector;
-	size_t raw_edid_size;
-	const struct edid *raw_edid;
-	uint64_t edid_blob_id;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_skip_on(check_analog_bridge(data, port));
-
-	connector = chamelium_port_get_connector(data->chamelium, port, true);
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob_id != 0);
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
-	raw_edid_size = edid_get_size(raw_edid);
-	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-}
-
-static void
-try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-		       enum igt_suspend_state state, enum igt_suspend_test test,
-		       struct udev_monitor *mon, bool connected)
-{
-	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
-						     DRM_MODE_CONNECTED;
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int delay;
-	int p;
-
-	igt_flush_uevents(mon);
-
-	delay = igt_get_autoresume_delay(state) * 1000 / 2;
-
-	if (port) {
-		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
-					      !connected);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			port = data->ports[p];
-			chamelium_schedule_hpd_toggle(data->chamelium, port,
-						      delay, !connected);
-		}
-
-		port = NULL;
-	}
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(wait_for_hotplug(mon, &timeout));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	if (port) {
-		igt_assert_eq(chamelium_reprobe_connector(&data->display,
-							  data->chamelium,
-							  port),
-							  target_state);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			drmModeConnection current_state;
-
-			port = data->ports[p];
-			/*
-			 * There could be as many hotplug events sent by
-			 * driver as connectors we scheduled an HPD toggle on
-			 * above, depending on timing. So if we're not seeing
-			 * the expected connector state try to wait for an HPD
-			 * event for each connector/port.
-			 */
-			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			if (p > 0 && current_state != target_state) {
-				igt_assert(wait_for_hotplug(mon, &timeout));
-				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			}
-
-			igt_assert_eq(current_state, target_state);
-		}
-
-		port = NULL;
-	}
-}
-
-static const char test_suspend_resume_hpd_desc[] =
-	"Toggle HPD during suspend, check that uevents are sent and connector "
-	"status is updated";
-static void
-test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-			enum igt_suspend_state state,
-			enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_hpd_common_desc[] =
-	"Toggle HPD during suspend on all connectors, check that uevents are "
-	"sent and connector status is updated";
-static void
-test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
-			       enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	struct chamelium_port *port;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		port = data->ports[p];
-		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_edid_change_desc[] =
-	"Simulate a screen being unplugged and another screen being plugged "
-	"during suspend, check that a uevent is sent and connector status is "
-	"updated";
-static void
-test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
-				enum igt_suspend_state state,
-				enum igt_suspend_test test,
-				enum igt_custom_edid_type edid,
-				enum igt_custom_edid_type alt_edid)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	bool link_status_failed[2][data->port_count];
-	int p;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Catch the event and flush all remaining ones. */
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_flush_uevents(mon);
-
-	/* First plug in the port */
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	/*
-	 * Change the edid before we suspend. On resume, the machine should
-	 * notice the EDID change and fire a hotplug event.
-	 */
-	set_edid(data, port, alt_edid);
-
-	get_connectors_link_status_failed(data, link_status_failed[0]);
-
-	igt_flush_uevents(mon);
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	get_connectors_link_status_failed(data, link_status_failed[1]);
-
-	for (p = 0; p < data->port_count; p++)
-		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
-}
-
-static igt_output_t *
-prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	/* The chamelium's default EDID has a lot of resolutions, way more then
-	 * we need to test. Additionally the default EDID doesn't support HDMI
-	 * audio.
-	 */
-	set_edid(data, port, edid);
-
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_display_reset(display);
-
-	output = get_output_for_port(data, port);
-
-	/* Refresh pipe to update connected status */
-	igt_output_set_pipe(output, PIPE_NONE);
-
-	pipe = get_pipe_for_output(display, output);
-	igt_output_set_pipe(output, pipe);
-
-	return output;
-}
-
-static void do_test_display(data_t *data, struct chamelium_port *port,
-			    igt_output_t *output, drmModeModeInfo *mode,
-			    uint32_t fourcc, enum chamelium_check check,
-			    int count)
-{
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb frame_fb, fb;
-	int i, fb_id, captured_frame_count;
-	int frame_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &fb);
-	igt_assert(fb_id > 0);
-
-	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
-				  DRM_FORMAT_MOD_LINEAR);
-	igt_assert(frame_id > 0);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-
-	enable_output(data, port, output, mode, &frame_fb);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		igt_crc_t *expected_crc;
-		igt_crc_t *crc;
-
-		/* We want to keep the display running for a little bit, since
-		 * there's always the potential the driver isn't able to keep
-		 * the display running properly for very long
-		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == count);
-
-		igt_debug("Captured %d frames\n", captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		for (i = 0; i < captured_frame_count; i++)
-			chamelium_assert_crc_eq_or_dump(data->chamelium,
-							expected_crc, &crc[i],
-							&fb, i);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_ANALOG ||
-		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		igt_assert(count == 1);
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-
-		if (check == CHAMELIUM_CHECK_ANALOG)
-			chamelium_crop_analog_frame(dump, mode->hdisplay,
-						    mode->vdisplay);
-
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	igt_remove_fb(data->drm_fd, &frame_fb);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static const char test_display_one_mode_desc[] =
-	"Pick the first mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_one_mode(data_t *data, struct chamelium_port *port,
-				  uint32_t fourcc, enum chamelium_check check,
-				  int count)
-{
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	igt_output_t *output;
-	igt_plane_t *primary;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
-
-	mode = &connector->modes[0];
-	if (check == CHAMELIUM_CHECK_ANALOG) {
-		bool bridge = check_analog_bridge(data, port);
-
-		igt_assert(!(bridge && prune_vga_mode(data, mode)));
-	}
-
-	do_test_display(data, port, output, mode, fourcc, check, count);
-
-	drmModeFreeConnector(connector);
-}
-
-static const char test_display_all_modes_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_all_modes(data_t *data, struct chamelium_port *port,
-				   uint32_t fourcc, enum chamelium_check check,
-				   int count)
-{
-	bool bridge;
-	int i, count_modes;
-
-	if (check == CHAMELIUM_CHECK_ANALOG)
-		bridge = check_analog_bridge(data, port);
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-		igt_require(igt_plane_has_format_mod(primary, fourcc,
-			    DRM_FORMAT_MOD_LINEAR));
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
-		    prune_vga_mode(data, mode))
-			continue;
-
-		do_test_display(data, port, output, mode, fourcc, check,
-				count);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-static const char test_display_frame_dump_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then download the captured frames and compare them "
-	"bit-by-bit to the sent ones";
-static void
-test_display_frame_dump(data_t *data, struct chamelium_port *port)
-{
-
-	int i, count_modes;
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		struct igt_fb fb;
-		struct chamelium_frame_dump *frame;
-		drmModeModeInfo *mode;
-		drmModeConnector *connector;
-		int fb_id, j;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Reading frame dumps from Chamelium...\n");
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
-		for (j = 0; j < 5; j++) {
-			frame = chamelium_read_captured_frame(data->chamelium,
-							      j);
-			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
-			chamelium_destroy_frame_dump(frame);
-		}
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
-
-static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
-		       drmModeModeInfo *mode)
-{
-	struct chamelium_video_params video_params = {0};
-	double mode_clock;
-	int mode_hsync_offset, mode_vsync_offset;
-	int mode_hsync_width, mode_vsync_width;
-	int mode_hsync_polarity, mode_vsync_polarity;
-
-	chamelium_port_get_video_params(chamelium, port, &video_params);
-
-	mode_clock = (double) mode->clock / 1000;
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
-		/* this is what chamelium understands as offsets for DP */
-		mode_hsync_offset = mode->htotal - mode->hsync_start;
-		mode_vsync_offset = mode->vtotal - mode->vsync_start;
-	} else {
-		/* and this is what they are for other connectors */
-		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
-		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
-	}
-
-	mode_hsync_width = mode->hsync_end - mode->hsync_start;
-	mode_vsync_width = mode->vsync_end - mode->vsync_start;
-
-	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-
-	igt_debug("Checking video mode:\n");
-	igt_debug("clock: got %f, expected %f ± %f%%\n",
-		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
-	igt_debug("hactive: got %d, expected %d\n",
-		  video_params.hactive, mode->hdisplay);
-	igt_debug("vactive: got %d, expected %d\n",
-		  video_params.vactive, mode->vdisplay);
-	igt_debug("hsync_offset: got %d, expected %d\n",
-		  video_params.hsync_offset, mode_hsync_offset);
-	igt_debug("vsync_offset: got %d, expected %d\n",
-		  video_params.vsync_offset, mode_vsync_offset);
-	igt_debug("htotal: got %d, expected %d\n",
-		  video_params.htotal, mode->htotal);
-	igt_debug("vtotal: got %d, expected %d\n",
-		  video_params.vtotal, mode->vtotal);
-	igt_debug("hsync_width: got %d, expected %d\n",
-		  video_params.hsync_width, mode_hsync_width);
-	igt_debug("vsync_width: got %d, expected %d\n",
-		  video_params.vsync_width, mode_vsync_width);
-	igt_debug("hsync_polarity: got %d, expected %d\n",
-		  video_params.hsync_polarity, mode_hsync_polarity);
-	igt_debug("vsync_polarity: got %d, expected %d\n",
-		  video_params.vsync_polarity, mode_vsync_polarity);
-
-	if (!isnan(video_params.clock)) {
-		igt_assert(video_params.clock >
-			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
-		igt_assert(video_params.clock <
-			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
-	}
-	igt_assert(video_params.hactive == mode->hdisplay);
-	igt_assert(video_params.vactive == mode->vdisplay);
-	igt_assert(video_params.hsync_offset == mode_hsync_offset);
-	igt_assert(video_params.vsync_offset == mode_vsync_offset);
-	igt_assert(video_params.htotal == mode->htotal);
-	igt_assert(video_params.vtotal == mode->vtotal);
-	igt_assert(video_params.hsync_width == mode_hsync_width);
-	igt_assert(video_params.vsync_width == mode_vsync_width);
-	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
-	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
-}
-
-static const char test_mode_timings_desc[] =
-	"For each mode of the IGT base EDID, perform a modeset and check the "
-	"mode detected by the Chamelium receiver matches the mode we set";
-static void test_mode_timings(data_t *data, struct chamelium_port *port)
-{
-	int i, count_modes;
-
-	i = 0;
-	igt_require(chamelium_supports_get_video_params(data->chamelium));
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-		int fb_id;
-		struct igt_fb fb;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port, false);
-		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		/* Trigger the FSM */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
-
-		check_mode(data->chamelium, port, mode);
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-struct vic_mode {
-	int hactive, vactive;
-	int vrefresh; /* Hz */
-	uint32_t picture_ar;
-};
-
-/* Maps Video Identification Codes to a mode */
-static const struct vic_mode vic_modes[] = {
-	[16] = {
-		.hactive = 1920,
-		.vactive = 1080,
-		.vrefresh = 60,
-		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
-	},
-};
-
-/* Maps aspect ratios to their mode flag */
-static const uint32_t mode_ar_flags[] = {
-	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
-};
-
-static enum infoframe_avi_picture_aspect_ratio
-get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
-{
-	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
-	switch (aspect_ratio) {
-	case DRM_MODE_PICTURE_ASPECT_4_3:
-		return INFOFRAME_AVI_PIC_AR_4_3;
-	case DRM_MODE_PICTURE_ASPECT_16_9:
-		return INFOFRAME_AVI_PIC_AR_16_9;
-	default:
-		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
-	}
-}
-
-static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
-				 drmModeModeInfo *drm_mode)
-{
-	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
-
-	return vic_mode->hactive == drm_mode->hdisplay &&
-	       vic_mode->vactive == drm_mode->vdisplay &&
-	       vic_mode->vrefresh == drm_mode->vrefresh &&
-	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
-}
-
-static const char test_display_aspect_ratio_desc[] =
-	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
-	"check they include the relevant fields";
-static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	int fb_id, i;
-	struct igt_fb fb;
-	bool found, ok;
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_avi infoframe_avi;
-	uint8_t vic = 16; /* TODO: test more VICs */
-	const struct vic_mode *vic_mode;
-	uint32_t aspect_ratio;
-	enum infoframe_avi_picture_aspect_ratio frame_ar;
-
-	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	vic_mode = &vic_modes[vic];
-	aspect_ratio = vic_mode->picture_ar;
-
-	found = false;
-	igt_assert(connector->count_modes > 0);
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-
-		if (vic_mode_matches_drm(vic_mode, mode)) {
-			found = true;
-			break;
-		}
-	}
-	igt_assert_f(found,
-		     "Failed to find mode with the correct aspect ratio\n");
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
-						 CHAMELIUM_INFOFRAME_AVI);
-	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
-
-	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
-				 infoframe->payload, infoframe->payload_size);
-	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
-
-	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
-
-	igt_debug("Checking AVI InfoFrame\n");
-	igt_debug("Picture aspect ratio: got %d, expected %d\n",
-		  infoframe_avi.picture_aspect_ratio, frame_ar);
-	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
-		  infoframe_avi.vic, vic);
-
-	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
-	igt_assert(infoframe_avi.vic == vic);
-
-	chamelium_infoframe_destroy(infoframe);
-	igt_remove_fb(data->drm_fd, &fb);
-	drmModeFreeConnector(connector);
-}
-
-
-/* Playback parameters control the audio signal we synthesize and send */
-#define PLAYBACK_CHANNELS 2
-#define PLAYBACK_SAMPLES 1024
-
-/* Capture paremeters control the audio signal we receive */
-#define CAPTURE_SAMPLES 2048
-
-#define AUDIO_TIMEOUT 2000 /* ms */
-/* A streak of 3 gives confidence that the signal is good. */
-#define MIN_STREAK 3
-
-#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
-#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
-#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
-
-/* TODO: enable >48KHz rates, these are not reliable */
-static int test_sampling_rates[] = {
-	32000,
-	44100,
-	48000,
-	/* 88200, */
-	/* 96000, */
-	/* 176400, */
-	/* 192000, */
-};
-
-static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
-
-/* Test frequencies (Hz): a sine signal will be generated for each.
- *
- * Depending on the sampling rate chosen, it might not be possible to properly
- * detect the generated sine (see Nyquist–Shannon sampling theorem).
- * Frequencies that can't be reliably detected will be automatically pruned in
- * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
- * tested with a 192KHz sampling rate.
- */
-static int test_frequencies[] = {
-	300,
-	600,
-	1200,
-	10000,
-	80000,
-};
-
-static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
-
-static const snd_pcm_format_t test_formats[] = {
-	SND_PCM_FORMAT_S16_LE,
-	SND_PCM_FORMAT_S24_LE,
-	SND_PCM_FORMAT_S32_LE,
-};
-
-static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
-
-struct audio_state {
-	struct alsa *alsa;
-	struct chamelium *chamelium;
-	struct chamelium_port *port;
-	struct chamelium_stream *stream;
-
-	/* The capture format is only available after capture has started. */
-	struct {
-		snd_pcm_format_t format;
-		int channels;
-		int rate;
-	} playback, capture;
-
-	char *name;
-	struct audio_signal *signal; /* for frequencies test only */
-	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	size_t recv_pages;
-	int msec;
-
-	int dump_fd;
-	char *dump_path;
-
-	pthread_t thread;
-	atomic_bool run;
-	atomic_bool positive; /* for pulse test only */
-};
-
-static void audio_state_init(struct audio_state *state, data_t *data,
-			     struct alsa *alsa, struct chamelium_port *port,
-			     snd_pcm_format_t format, int channels, int rate)
-{
-	memset(state, 0, sizeof(*state));
-	state->dump_fd = -1;
-
-	state->alsa = alsa;
-	state->chamelium = data->chamelium;
-	state->port = port;
-
-	state->playback.format = format;
-	state->playback.channels = channels;
-	state->playback.rate = rate;
-
-	alsa_configure_output(alsa, format, channels, rate);
-
-	state->stream = chamelium_stream_init();
-	igt_assert_f(state->stream,
-		     "Failed to initialize Chamelium stream client\n");
-}
-
-static void audio_state_fini(struct audio_state *state)
-{
-	chamelium_stream_deinit(state->stream);
-	free(state->name);
-}
-
-static void *run_audio_thread(void *data)
-{
-	struct alsa *alsa = data;
-
-	alsa_run(alsa, -1);
-	return NULL;
-}
-
-static void audio_state_start(struct audio_state *state, const char *name)
-{
-	int ret;
-	bool ok;
-	size_t i, j;
-	enum chamelium_stream_realtime_mode stream_mode;
-	char dump_suffix[64];
-
-	free(state->name);
-	state->name = strdup(name);
-	state->recv_pages = 0;
-	state->msec = 0;
-
-	igt_debug("Starting %s test with playback format %s, "
-		  "sampling rate %d Hz and %d channels\n",
-		  name, snd_pcm_format_name(state->playback.format),
-		  state->playback.rate, state->playback.channels);
-
-	chamelium_start_capturing_audio(state->chamelium, state->port, false);
-
-	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
-	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
-	igt_assert_f(ok, "Failed to start streaming audio capture\n");
-
-	/* Start playing audio */
-	state->run = true;
-	ret = pthread_create(&state->thread, NULL,
-			     run_audio_thread, state->alsa);
-	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
-
-	/* The Chamelium device only supports this PCM format. */
-	state->capture.format = SND_PCM_FORMAT_S32_LE;
-
-	/* Only after we've started playing audio, we can retrieve the capture
-	 * format used by the Chamelium device. */
-	chamelium_get_audio_format(state->chamelium, state->port,
-				   &state->capture.rate,
-				   &state->capture.channels);
-	if (state->capture.rate == 0) {
-		igt_debug("Audio receiver doesn't indicate the capture "
-			 "sampling rate, assuming it's %d Hz\n",
-			 state->playback.rate);
-		state->capture.rate = state->playback.rate;
-	}
-
-	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
-					    state->channel_mapping);
-	/* Make sure we can capture all channels we send. */
-	for (i = 0; i < state->playback.channels; i++) {
-		ok = false;
-		for (j = 0; j < state->capture.channels; j++) {
-			if (state->channel_mapping[j] == i) {
-				ok = true;
-				break;
-			}
-		}
-		igt_assert_f(ok, "Cannot capture all channels\n");
-	}
-
-	if (igt_frame_dump_is_enabled()) {
-		snprintf(dump_suffix, sizeof(dump_suffix),
-			 "capture-%s-%s-%dch-%dHz",
-			 name, snd_pcm_format_name(state->playback.format),
-			 state->playback.channels, state->playback.rate);
-
-		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
-							      state->capture.rate,
-							      state->capture.channels,
-							      &state->dump_path);
-		igt_assert_f(state->dump_fd >= 0,
-			     "Failed to create audio dump file\n");
-	}
-}
-
-static void audio_state_receive(struct audio_state *state,
-				int32_t **recv, size_t *recv_len)
-{
-	bool ok;
-	size_t page_count;
-	size_t recv_size;
-
-	ok = chamelium_stream_receive_realtime_audio(state->stream,
-						     &page_count,
-						     recv, recv_len);
-	igt_assert_f(ok, "Failed to receive audio from stream server\n");
-
-	state->msec = state->recv_pages * *recv_len
-		      / (double) state->capture.channels
-		      / (double) state->capture.rate * 1000;
-	state->recv_pages++;
-
-	if (state->dump_fd >= 0) {
-		recv_size = *recv_len * sizeof(int32_t);
-		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
-			     "Failed to write to audio dump file\n");
-	}
-}
-
-static void audio_state_stop(struct audio_state *state, bool success)
-{
-	bool ok;
-	int ret;
-	struct chamelium_audio_file *audio_file;
-	enum igt_log_level log_level;
-
-	igt_debug("Stopping audio playback\n");
-	state->run = false;
-	ret = pthread_join(state->thread, NULL);
-	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
-
-	ok = chamelium_stream_stop_realtime_audio(state->stream);
-	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
-
-	audio_file = chamelium_stop_capturing_audio(state->chamelium,
-						    state->port);
-	if (audio_file) {
-		igt_debug("Audio file saved on the Chamelium in %s\n",
-			  audio_file->path);
-		chamelium_destroy_audio_file(audio_file);
-	}
-
-	if (state->dump_fd >= 0) {
-		close(state->dump_fd);
-		state->dump_fd = -1;
-
-		if (success) {
-			/* Test succeeded, no need to keep the captured data */
-			unlink(state->dump_path);
-		} else
-			igt_debug("Saved captured audio data to %s\n",
-				  state->dump_path);
-		free(state->dump_path);
-		state->dump_path = NULL;
-	}
-
-	if (success)
-		log_level = IGT_LOG_DEBUG;
-	else
-		log_level = IGT_LOG_CRITICAL;
-
-	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
-		"sampling rate %d Hz and %d channels: %s\n",
-		state->name, snd_pcm_format_name(state->playback.format),
-		state->playback.rate, state->playback.channels,
-		success ? "ALL GREEN" : "FAILED");
-
-}
-
-static void check_audio_infoframe(struct audio_state *state)
-{
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_audio infoframe_audio;
-	struct infoframe_audio expected = {0};
-	bool ok;
-
-	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
-		igt_debug("Skipping audio InfoFrame check: "
-			  "Chamelium board doesn't support GetLastInfoFrame\n");
-		return;
-	}
-
-	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
-	expected.channel_count = state->playback.channels;
-	expected.sampling_freq = state->playback.rate;
-	expected.sample_size = snd_pcm_format_width(state->playback.format);
-
-	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
-						 CHAMELIUM_INFOFRAME_AUDIO);
-	if (infoframe == NULL && state->playback.channels <= 2) {
-		/* Audio InfoFrames are optional for mono and stereo audio */
-		igt_debug("Skipping audio InfoFrame check: "
-			  "no InfoFrame received\n");
-		return;
-	}
-	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
-
-	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
-				   infoframe->payload, infoframe->payload_size);
-	chamelium_infoframe_destroy(infoframe);
-	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
-
-	igt_debug("Checking audio InfoFrame:\n");
-	igt_debug("coding_type: got %d, expected %d\n",
-		  infoframe_audio.coding_type, expected.coding_type);
-	igt_debug("channel_count: got %d, expected %d\n",
-		  infoframe_audio.channel_count, expected.channel_count);
-	igt_debug("sampling_freq: got %d, expected %d\n",
-		  infoframe_audio.sampling_freq, expected.sampling_freq);
-	igt_debug("sample_size: got %d, expected %d\n",
-		  infoframe_audio.sample_size, expected.sample_size);
-
-	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
-		igt_assert(infoframe_audio.coding_type == expected.coding_type);
-	if (infoframe_audio.channel_count >= 0)
-		igt_assert(infoframe_audio.channel_count == expected.channel_count);
-	if (infoframe_audio.sampling_freq >= 0)
-		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
-	if (infoframe_audio.sample_size >= 0)
-		igt_assert(infoframe_audio.sample_size == expected.sample_size);
-}
-
-static int
-audio_output_frequencies_callback(void *data, void *buffer, int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	audio_signal_fill(state->signal, tmp, samples);
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool test_audio_frequencies(struct audio_state *state)
-{
-	int freq, step;
-	int32_t *recv, *buf;
-	double *channel;
-	size_t i, j, streak;
-	size_t recv_len, buf_len, buf_cap, channel_len;
-	bool success;
-	int capture_chan;
-
-	state->signal = audio_signal_init(state->playback.channels,
-					  state->playback.rate);
-	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
-
-	/* We'll choose different frequencies per channel to make sure they are
-	 * independent from each other. To do so, we'll add a different offset
-	 * to the base frequencies for each channel. We need to choose a big
-	 * enough offset so that we're sure to detect mixed up channels. We
-	 * choose an offset of two 2 bins in the final FFT to enforce a clear
-	 * difference.
-	 *
-	 * Note that we assume capture_rate == playback_rate. We'll assert this
-	 * later on. We cannot retrieve the capture rate before starting
-	 * playing audio, so we don't really have the choice.
-	 */
-	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
-	for (i = 0; i < test_frequencies_count; i++) {
-		for (j = 0; j < state->playback.channels; j++) {
-			freq = test_frequencies[i] + j * step;
-			audio_signal_add_frequency(state->signal, freq, j);
-		}
-	}
-	audio_signal_synthesize(state->signal);
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_frequencies_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	audio_state_start(state, "frequencies");
-
-	igt_assert_f(state->capture.rate == state->playback.rate,
-		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
-		     state->capture.rate, state->playback.rate);
-
-	/* Needs to be a multiple of 128, because that's the number of samples
-	 * we get per channel each time we receive an audio page from the
-	 * Chamelium device.
-	 *
-	 * Additionally, this value needs to be high enough to guarantee we
-	 * capture a full period of each sine we generate. If we capture 2048
-	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
-	 * sines. For lower sampling rates, the capture duration will be
-	 * longer.
-	 */
-	channel_len = CAPTURE_SAMPLES;
-	channel = malloc(sizeof(double) * channel_len);
-
-	buf_cap = state->capture.channels * channel_len;
-	buf = malloc(sizeof(int32_t) * buf_cap);
-	buf_len = 0;
-
-	recv = NULL;
-	recv_len = 0;
-
-	success = false;
-	streak = 0;
-	while (!success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
-		buf_len += recv_len;
-
-		if (buf_len < buf_cap)
-			continue;
-		igt_assert(buf_len == buf_cap);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (j = 0; j < state->playback.channels; j++) {
-			capture_chan = state->channel_mapping[j];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", j, capture_chan);
-
-			audio_extract_channel_s32_le(channel, channel_len,
-						     buf, buf_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			if (audio_signal_detect(state->signal,
-						state->capture.rate, j,
-						channel, channel_len))
-				streak++;
-			else
-				streak = 0;
-		}
-
-		buf_len = 0;
-
-		success = streak == MIN_STREAK * state->playback.channels;
-	}
-
-	audio_state_stop(state, success);
-
-	free(recv);
-	free(buf);
-	free(channel);
-	audio_signal_fini(state->signal);
-
-	check_audio_infoframe(state);
-
-	return success;
-}
-
-static int audio_output_flatline_callback(void *data, void *buffer,
-					     int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len, i;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	for (i = 0; i < len; i++)
-		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
-{
-	double expected, min, max;
-	size_t i;
-	bool ok;
-
-	min = max = NAN;
-	for (i = 0; i < buf_len; i++) {
-		if (isnan(min) || buf[i] < min)
-			min = buf[i];
-		if (isnan(max) || buf[i] > max)
-			max = buf[i];
-	}
-
-	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
-	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
-	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
-	if (ok)
-		igt_debug("Flatline wave amplitude detected\n");
-	else
-		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
-			  min, max);
-	return ok;
-}
-
-static ssize_t detect_falling_edge(double *buf, size_t buf_len)
-{
-	size_t i;
-
-	for (i = 0; i < buf_len; i++) {
-		if (buf[i] < 0)
-			return i;
-	}
-
-	return -1;
-}
-
-/** test_audio_flatline:
- *
- * Send a constant value (one positive, then a negative one) and check that:
- *
- * - The amplitude of the flatline is correct
- * - All channels switch from a positive signal to a negative one at the same
- *   time (ie. all channels are aligned)
- */
-static bool test_audio_flatline(struct audio_state *state)
-{
-	bool success, amp_success, align_success;
-	int32_t *recv;
-	size_t recv_len, i, channel_len;
-	ssize_t j;
-	int streak, capture_chan;
-	double *channel;
-	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_flatline_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	/* Start by sending a positive signal */
-	state->positive = true;
-
-	audio_state_start(state, "flatline");
-
-	for (i = 0; i < state->playback.channels; i++)
-		falling_edges[i] = -1;
-
-	recv = NULL;
-	recv_len = 0;
-	amp_success = false;
-	streak = 0;
-	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (i = 0; i < state->playback.channels; i++) {
-			capture_chan = state->channel_mapping[i];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", i, capture_chan);
-
-			channel_len = audio_extract_channel_s32_le(NULL, 0,
-								   recv, recv_len,
-								   state->capture.channels,
-								   capture_chan);
-			channel = malloc(channel_len * sizeof(double));
-			audio_extract_channel_s32_le(channel, channel_len,
-						     recv, recv_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			/* Check whether the amplitude is fine */
-			if (detect_flatline_amplitude(channel, channel_len,
-						      state->positive))
-				streak++;
-			else
-				streak = 0;
-
-			/* If we're now sending a negative signal, detect the
-			 * falling edge */
-			j = detect_falling_edge(channel, channel_len);
-			if (!state->positive && j >= 0) {
-				falling_edges[i] = recv_len * state->recv_pages
-						   + j;
-			}
-
-			free(channel);
-		}
-
-		amp_success = streak == MIN_STREAK * state->playback.channels;
-
-		if (amp_success && state->positive) {
-			/* Switch to a negative signal after we've detected the
-			 * positive one. */
-			state->positive = false;
-			amp_success = false;
-			streak = 0;
-			igt_debug("Switching to negative square wave\n");
-		}
-	}
-
-	/* Check alignment between all channels by comparing the index of the
-	 * falling edge. */
-	align_success = true;
-	for (i = 0; i < state->playback.channels; i++) {
-		if (falling_edges[i] < 0) {
-			igt_critical("Falling edge not detected for channel %zu\n",
-				     i);
-			align_success = false;
-			continue;
-		}
-
-		if (abs(falling_edges[0] - falling_edges[i]) >
-		    FLATLINE_ALIGN_ACCURACY) {
-			igt_critical("Channel alignment mismatch: "
-				     "channel 0 has a falling edge at index %d "
-				     "while channel %zu has index %d\n",
-				     falling_edges[0], i, falling_edges[i]);
-			align_success = false;
-		}
-	}
-
-	success = amp_success && align_success;
-	audio_state_stop(state, success);
-
-	free(recv);
-
-	return success;
-}
-
-static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
-				      int channels, int sampling_rate)
-{
-	if (!alsa_test_output_configuration(alsa, format, channels,
-					    sampling_rate)) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because at least one of the "
-			  "selected output devices doesn't support this "
-			  "configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	/* TODO: the Chamelium device sends a malformed signal for some audio
-	 * configurations. See crbug.com/950917 */
-	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
-			channels > 2) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because the Chamelium device "
-			  "doesn't support this configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	return true;
-}
-
-static const char test_display_audio_desc[] =
-	"Playback various audio signals with various audio formats/rates, "
-	"capture them and check they are correct";
-static void
-test_display_audio(data_t *data, struct chamelium_port *port,
-		   const char *audio_device, enum igt_custom_edid_type edid)
-{
-	bool run, success;
-	struct alsa *alsa;
-	int ret;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j;
-	int channels, sampling_rate;
-	snd_pcm_format_t format;
-	struct audio_state state;
-
-	igt_require(alsa_has_exclusive_access());
-
-	/* Old Chamelium devices need an update for DisplayPort audio and
-	 * chamelium_get_audio_format support. */
-	igt_require(chamelium_has_audio_support(data->chamelium, port));
-
-	alsa = alsa_init();
-	igt_assert(alsa);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because the receiver won't try to receive audio if
-	 * it doesn't receive video. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	run = false;
-	success = true;
-	for (i = 0; i < test_sampling_rates_count; i++) {
-		for (j = 0; j < test_formats_count; j++) {
-			ret = alsa_open_output(alsa, audio_device);
-			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
-
-			/* TODO: playback on all 8 available channels (this
-			 * isn't supported by Chamelium devices yet, see
-			 * https://crbug.com/950917) */
-			format = test_formats[j];
-			channels = PLAYBACK_CHANNELS;
-			sampling_rate = test_sampling_rates[i];
-
-			if (!check_audio_configuration(alsa, format, channels,
-						       sampling_rate))
-				continue;
-
-			run = true;
-
-			audio_state_init(&state, data, alsa, port,
-					 format, channels, sampling_rate);
-			success &= test_audio_frequencies(&state);
-			success &= test_audio_flatline(&state);
-			audio_state_fini(&state);
-
-			alsa_close_output(alsa);
-		}
-	}
-
-	/* Make sure we tested at least one frequency and format. */
-	igt_assert(run);
-	/* Make sure all runs were successful. */
-	igt_assert(success);
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-
-	free(alsa);
-}
-
-static const char test_display_audio_edid_desc[] =
-	"Plug a connector with an EDID suitable for audio, check ALSA's "
-	"EDID-Like Data reports the correct audio parameters";
-static void
-test_display_audio_edid(data_t *data, struct chamelium_port *port,
-			enum igt_custom_edid_type edid)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id;
-	struct eld_entry eld;
-	struct eld_sad *sad;
-
-	igt_require(eld_is_supported());
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because audio cannot be played on inactive
-	 * connectors. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	igt_assert(eld_get_igt(&eld));
-	igt_assert(eld.sads_len == 1);
-
-	sad = &eld.sads[0];
-	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
-	igt_assert(sad->channels == 2);
-	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
-		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
-	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
-		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-}
-
-static void randomize_plane_stride(data_t *data,
-				   uint32_t width, uint32_t height,
-				   uint32_t format, uint64_t modifier,
-				   size_t *stride)
-{
-	size_t stride_min;
-	uint32_t max_tile_w = 4, tile_w, tile_h;
-	int i;
-	struct igt_fb dummy;
-
-	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
-
-	/* Randomize the stride to less than twice the minimum. */
-	*stride = (rand() % stride_min) + stride_min;
-
-	/*
-	 * Create a dummy FB to determine bpp for each plane, and calculate
-	 * the maximum tile width from that.
-	 */
-	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
-	for (i = 0; i < dummy.num_planes; i++) {
-		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
-
-		if (tile_w > max_tile_w)
-			max_tile_w = tile_w;
-	}
-	igt_remove_fb(data->drm_fd, &dummy);
-
-	/*
-	 * Pixman requires the stride to be aligned to 32-bits, which is
-	 * reflected in the initial value of max_tile_w and the hw
-	 * may require a multiple of tile width, choose biggest of the 2.
-	 */
-	*stride = ALIGN(*stride, max_tile_w);
-}
-
-static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
-				  uint32_t height, uint32_t format,
-				  uint64_t *modifier)
-{
-	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
-		/* Randomize the column height to less than twice the minimum. */
-		size_t column_height = (rand() % height) + height;
-
-		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
-			  column_height);
-
-		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
-	}
-}
-
-static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
-				  drmModeModeInfo *mode,
-				  uint32_t *width, uint32_t *height,
-				  uint32_t *format, uint64_t *modifier,
-				  bool allow_yuv)
-{
-	int min_dim;
-	uint32_t idx[plane->format_mod_count];
-	unsigned int count = 0;
-	unsigned int i;
-
-	/* First pass to count the supported formats. */
-	for (i = 0; i < plane->format_mod_count; i++)
-		if (igt_fb_supported_format(plane->formats[i]) &&
-		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
-			idx[count++] = i;
-
-	igt_assert(count > 0);
-
-	i = idx[rand() % count];
-	*format = plane->formats[i];
-	*modifier = plane->modifiers[i];
-
-	update_tiled_modifier(plane, *width, *height, *format, modifier);
-
-	/*
-	 * Randomize width and height in the mode dimensions range.
-	 *
-	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
-	 * least min_dim, because src_w = width - (rand % w / 2).
-	 *
-	 * Use a minimum dimension of 16 for YUV, because planar YUV
-	 * subsamples the UV plane.
-	 */
-	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
-
-	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
-	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
-}
-
-static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
-			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
-			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
-			    struct igt_fb *fb)
-{
-	igt_plane_set_fb(plane, fb);
-
-	igt_plane_set_position(plane, crtc_x, crtc_y);
-	igt_plane_set_size(plane, crtc_w, crtc_h);
-
-	igt_fb_set_position(fb, plane, src_x, src_y);
-	igt_fb_set_size(fb, plane, src_w, src_h);
-}
-
-static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
-					drmModeModeInfo *mode,
-					struct igt_fb *fb,
-					uint32_t *src_w, uint32_t *src_h,
-					uint32_t *src_x, uint32_t *src_y,
-					uint32_t *crtc_w, uint32_t *crtc_h,
-					int32_t *crtc_x, int32_t *crtc_y,
-					bool allow_scaling)
-{
-	bool is_yuv = igt_format_is_yuv(fb->drm_format);
-	uint32_t width = fb->width, height = fb->height;
-	double ratio;
-	int ret;
-
-	/* Randomize source offset in the first half of the original size. */
-	*src_x = rand() % (width / 2);
-	*src_y = rand() % (height / 2);
-
-	/* The source size only includes the active source area. */
-	*src_w = width - *src_x;
-	*src_h = height - *src_y;
-
-	if (allow_scaling) {
-		*crtc_w = (rand() % mode->hdisplay) + 1;
-		*crtc_h = (rand() % mode->vdisplay) + 1;
-
-		/*
-		 * Don't bother with scaling if dimensions are quite close in
-		 * order to get non-scaling cases more frequently. Also limit
-		 * scaling to 3x to avoid agressive filtering that makes
-		 * comparison less reliable, and don't go above 2x downsampling
-		 * to avoid possible hw limitations.
-		 */
-
-		ratio = ((double) *crtc_w / *src_w);
-		if (ratio < 0.5)
-			*src_w = *crtc_w * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_w = *src_w;
-		else if (ratio > 3.0)
-			*crtc_w = *src_w * 3;
-
-		ratio = ((double) *crtc_h / *src_h);
-		if (ratio < 0.5)
-			*src_h = *crtc_h * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_h = *src_h;
-		else if (ratio > 3.0)
-			*crtc_h = *src_h * 3;
-	} else {
-		*crtc_w = *src_w;
-		*crtc_h = *src_h;
-	}
-
-	if (*crtc_w != *src_w || *crtc_h != *src_h) {
-		/*
-		 * When scaling is involved, make sure to not go off-bounds or
-		 * scaled clipping may result in decimal dimensions, that most
-		 * drivers don't support.
-		 */
-		if (*crtc_w < mode->hdisplay)
-			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
-		else
-			*crtc_x = 0;
-
-		if (*crtc_h < mode->vdisplay)
-			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
-		else
-			*crtc_y = 0;
-	} else {
-		/*
-		 * Randomize the on-crtc position and allow the plane to go
-		 * off-display by less than half of its on-crtc dimensions.
-		 */
-		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
-		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
-	}
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
-			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
-	ret = igt_display_try_commit_atomic(&data->display,
-					    DRM_MODE_ATOMIC_TEST_ONLY |
-					    DRM_MODE_ATOMIC_ALLOW_MODESET,
-					    NULL);
-	if (!ret)
-		return;
-
-	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
-	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
-
-	/* Make YUV coordinates a multiple of 2 and retry the math. */
-	if (is_yuv) {
-		*src_x &= ~1;
-		*src_y &= ~1;
-		*src_w &= ~1;
-		*src_h &= ~1;
-		/* To handle 1:1 scaling, clear crtc_w/h too. */
-		*crtc_w &= ~1;
-		*crtc_h &= ~1;
-
-		if (*crtc_x < 0 && (*crtc_x & 1))
-			(*crtc_x)++;
-		else
-			*crtc_x &= ~1;
-
-		/* If negative, round up to 0 instead of down */
-		if (*crtc_y < 0 && (*crtc_y & 1))
-			(*crtc_y)++;
-		else
-			*crtc_y &= ~1;
-
-		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-				*crtc_h, *crtc_x, *crtc_y, fb);
-		ret = igt_display_try_commit_atomic(&data->display,
-						DRM_MODE_ATOMIC_TEST_ONLY |
-						DRM_MODE_ATOMIC_ALLOW_MODESET,
-						NULL);
-		if (!ret)
-			return;
-	}
-
-	igt_assert(!ret || allow_scaling);
-	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
-		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
-
-	*crtc_w = *src_w;
-	*crtc_h = *src_h;
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-			*crtc_h, *crtc_x, *crtc_y, fb);
-	igt_display_commit_atomic(&data->display,
-				  DRM_MODE_ATOMIC_TEST_ONLY |
-				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-}
-
-static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
-			     uint32_t src_w, uint32_t src_h,
-			     uint32_t src_x, uint32_t src_y,
-			     uint32_t crtc_w, uint32_t crtc_h,
-			     int32_t crtc_x, int32_t crtc_y,
-			     struct igt_fb *fb)
-{
-	cairo_surface_t *surface;
-	cairo_surface_t *clipped_surface;
-	cairo_t *cr;
-
-	surface = igt_get_cairo_surface(data->drm_fd, fb);
-
-	if (src_x || src_y) {
-		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
-							     src_w, src_h);
-
-		cr = cairo_create(clipped_surface);
-
-		cairo_translate(cr, -1. * src_x, -1. * src_y);
-
-		cairo_set_source_surface(cr, surface, 0, 0);
-
-		cairo_paint(cr);
-		cairo_surface_flush(clipped_surface);
-
-		cairo_destroy(cr);
-	} else {
-		clipped_surface = surface;
-	}
-
-	cr = cairo_create(result);
-
-	cairo_translate(cr, crtc_x, crtc_y);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_scale(cr, (double) crtc_w / src_w,
-			    (double) crtc_h / src_h);
-	}
-
-	cairo_set_source_surface(cr, clipped_surface, 0, 0);
-	cairo_surface_destroy(clipped_surface);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_pattern_set_filter(cairo_get_source(cr),
-					 CAIRO_FILTER_BILINEAR);
-		cairo_pattern_set_extend(cairo_get_source(cr),
-					 CAIRO_EXTEND_NONE);
-	}
-
-	cairo_paint(cr);
-	cairo_surface_flush(result);
-
-	cairo_destroy(cr);
-}
-
-static void prepare_randomized_plane(data_t *data,
-				     drmModeModeInfo *mode,
-				     igt_plane_t *plane,
-				     struct igt_fb *overlay_fb,
-				     unsigned int index,
-				     cairo_surface_t *result_surface,
-				     bool allow_scaling, bool allow_yuv)
-{
-	struct igt_fb pattern_fb;
-	uint32_t overlay_fb_w, overlay_fb_h;
-	uint32_t overlay_src_w, overlay_src_h;
-	uint32_t overlay_src_x, overlay_src_y;
-	int32_t overlay_crtc_x, overlay_crtc_y;
-	uint32_t overlay_crtc_w, overlay_crtc_h;
-	uint32_t format;
-	uint64_t modifier;
-	size_t stride;
-	bool tiled;
-	int fb_id;
-
-	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
-			      &format, &modifier, allow_yuv);
-
-	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
-	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
-		  index, overlay_fb_w, overlay_fb_h,
-		  igt_format_str(format), tiled ? "tiled" : "linear");
-
-	/* Get a pattern framebuffer for the overlay plane. */
-	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
-					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
-			       format, modifier, &stride);
-
-	igt_debug("Plane %d: stride %ld\n", index, stride);
-
-	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
-					   modifier, stride);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_coordinates(data, plane, mode, overlay_fb,
-				    &overlay_src_w, &overlay_src_h,
-				    &overlay_src_x, &overlay_src_y,
-				    &overlay_crtc_w, &overlay_crtc_h,
-				    &overlay_crtc_x, &overlay_crtc_y,
-				    allow_scaling);
-
-	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
-		  overlay_src_w, overlay_src_h);
-	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
-		  overlay_src_x, overlay_src_y);
-	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
-		  overlay_crtc_w, overlay_crtc_h);
-	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
-		  overlay_crtc_x, overlay_crtc_y);
-
-	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
-			 overlay_src_x, overlay_src_y,
-			 overlay_crtc_w, overlay_crtc_h,
-			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
-
-	/* Remove the original pattern framebuffer. */
-	igt_remove_fb(data->drm_fd, &pattern_fb);
-}
-
-static const char test_display_planes_random_desc[] =
-	"Setup a few overlay planes with random parameters, capture the frame "
-	"and check it matches the expected output";
-static void test_display_planes_random(data_t *data,
-				       struct chamelium_port *port,
-				       enum chamelium_check check)
-{
-	igt_output_t *output;
-	drmModeModeInfo *mode;
-	igt_plane_t *primary_plane;
-	struct igt_fb primary_fb;
-	struct igt_fb result_fb;
-	struct igt_fb *overlay_fbs;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	unsigned int overlay_planes_max = 0;
-	unsigned int overlay_planes_count;
-	cairo_surface_t *result_surface;
-	int captured_frame_count;
-	bool allow_scaling;
-	bool allow_yuv;
-	unsigned int i;
-	unsigned int fb_id;
-
-	switch (check) {
-	case CHAMELIUM_CHECK_CRC:
-		allow_scaling = false;
-		allow_yuv = false;
-		break;
-	case CHAMELIUM_CHECK_CHECKERBOARD:
-		allow_scaling = true;
-		allow_yuv = true;
-		break;
-	default:
-		igt_assert(false);
-	}
-
-	srand(time(NULL));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Find the connector and pipe. */
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-
-	mode = igt_output_get_mode(output);
-
-	/* Get a framebuffer for the primary plane. */
-	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary_plane);
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
-	igt_assert(fb_id > 0);
-
-	/* Get a framebuffer for the cairo composition result. */
-	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
-			      mode->vdisplay, DRM_FORMAT_XRGB8888,
-			      DRM_FORMAT_MOD_LINEAR, &result_fb);
-	igt_assert(fb_id > 0);
-
-	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
-
-	/* Paint the primary framebuffer on the result surface. */
-	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
-			 &primary_fb);
-
-	/* Configure the primary plane. */
-	igt_plane_set_fb(primary_plane, &primary_fb);
-
-	overlay_planes_max =
-		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
-
-	/* Limit the number of planes to a reasonable scene. */
-	overlay_planes_max = min(overlay_planes_max, 4u);
-
-	overlay_planes_count = (rand() % overlay_planes_max) + 1;
-	igt_debug("Using %d overlay planes\n", overlay_planes_count);
-
-	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
-
-	for (i = 0; i < overlay_planes_count; i++) {
-		struct igt_fb *overlay_fb = &overlay_fbs[i];
-		igt_plane_t *plane =
-			igt_output_get_plane_type_index(output,
-							DRM_PLANE_TYPE_OVERLAY,
-							i);
-		igt_assert(plane);
-
-		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
-					 result_surface, allow_scaling,
-					 allow_yuv);
-	}
-
-	cairo_surface_destroy(result_surface);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&result_fb);
-
-	igt_display_commit2(&data->display, COMMIT_ATOMIC);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == 1);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium,
-						expected_crc, crc,
-						&result_fb, 0);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &result_fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	for (i = 0; i < overlay_planes_count; i++)
-		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
-
-	free(overlay_fbs);
-
-	igt_remove_fb(data->drm_fd, &primary_fb);
-	igt_remove_fb(data->drm_fd, &result_fb);
-}
-
-static const char test_hpd_without_ddc_desc[] =
-	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
-static void
-test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-	igt_flush_uevents(mon);
-
-	/* Disable the DDC on the connector and make sure we still get a
-	 * hotplug
-	 */
-	chamelium_port_set_ddc_state(data->chamelium, port, false);
-	chamelium_plug(data->chamelium, port);
-
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_assert_eq(chamelium_reprobe_connector(&data->display,
-						  data->chamelium, port),
-						  DRM_MODE_CONNECTED);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_hpd_storm_detect_desc[] =
-	"Trigger a series of hotplugs in a very small timeframe to simulate a"
-	"bad cable, check the kernel falls back to polling to avoid a hotplug "
-	"storm";
-static void
-test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
-{
-	struct udev_monitor *mon;
-	int count = 0;
-
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 1);
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-	igt_assert(igt_hpd_storm_detected(data->drm_fd));
-
-	mon = igt_watch_uevents();
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-
-	/*
-	 * Polling should have been enabled by the HPD storm at this point,
-	 * so we should only get at most 1 hotplug event
-	 */
-	igt_until_timeout(5)
-		count += igt_hotplug_detected(mon, 1);
-	igt_assert_lt(count, 2);
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_hpd_storm_disable_desc[] =
-	"Disable HPD storm detection, trigger a storm and check the kernel "
-	"doesn't detect one";
-static void
-test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
-{
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	chamelium_fire_hpd_pulses(data->chamelium, port,
-				  width, 10);
-	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
-
-	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,
-				   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;
-
-		monitor_edid *edid = &edids_list[i];
-		igt_info("Testing out the EDID for %s\n",
-			 monitor_edid_get_name(edid));
-
-		/* Getting and Setting the EDID on Chamelium. */
-		chamelium_edid =
-			get_chameleon_edid_from_monitor_edid(chamelium, 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);
-}
-
-static const char igt_edid_resolution_list_desc[] =
-	"Get an EDID with many modes of different configurations, set them on the screen and check the"
-	" screen resolution matches the mode resolution.";
-
-static void edid_resolution_list(data_t *data, struct chamelium_port *port)
-{
-	struct chamelium *chamelium = data->chamelium;
-	struct udev_monitor *mon = igt_watch_uevents();
-	drmModeConnector *connector;
-	drmModeModeInfoPtr modes;
-	int count_modes;
-	int i;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	chamelium_unplug(chamelium, port);
-	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
-
-	igt_flush_uevents(mon);
-	chamelium_plug(chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
-	igt_flush_uevents(mon);
-
-	connector = chamelium_port_get_connector(chamelium, port, true);
-	modes = connector->modes;
-	count_modes = connector->count_modes;
-
-	output = get_output_for_port(data, port);
-	pipe = get_pipe_for_output(&data->display, output);
-	igt_output_set_pipe(output, pipe);
-
-	for (i = 0; i < count_modes; ++i)
-		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
-
-	for (i = 0; i < count_modes; ++i) {
-		struct igt_fb fb = { 0 };
-		bool is_video_stable;
-		int screen_res_w, screen_res_h;
-
-		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
-			 modes[i].vrefresh);
-
-		/* Set the screen mode with the one we chose. */
-		create_fb_for_mode(data, &fb, &modes[i]);
-		enable_output(data, port, output, &modes[i], &fb);
-		is_video_stable = chamelium_port_wait_video_input_stable(
-			chamelium, port, 10);
-		igt_assert(is_video_stable);
-
-		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
-					      &screen_res_h);
-		igt_assert_eq(screen_res_w, modes[i].hdisplay);
-		igt_assert_eq(screen_res_h, modes[i].vdisplay);
-
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	drmModeFreeConnector(connector);
-}
-
-#define for_each_port(p, port)            \
-	for (p = 0, port = data.ports[p]; \
-	     p < data.port_count;         \
-	     p++, port = data.ports[p])
-
-#define connector_subtest(name__, type__)                    \
-	igt_subtest(name__)                                  \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-#define connector_dynamic_subtest(name__, type__)            \
-	igt_subtest_with_dynamic(name__)                     \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-
-static data_t data;
-
-IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
-igt_main
-{
-	struct chamelium_port *port;
-	int p;
-	size_t i;
-
-	igt_fixture {
-		/* So fbcon doesn't try to reprobe things itself */
-		kmstest_set_vt_graphics_mode();
-
-		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
-
-		/*
-		 * XXX: disabling modeset, can be removed when
-		 * igt_display_require will start doing this for us
-		 */
-		igt_display_commit2(&data.display, COMMIT_ATOMIC);
-
-		/* we need to initalize chamelium after igt_display_require */
-		data.chamelium = chamelium_init(data.drm_fd, &data.display);
-		igt_require(data.chamelium);
-
-		data.ports = chamelium_get_ports(data.chamelium,
-						 &data.port_count);
-
-		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
-			data.edids[i] = chamelium_new_edid(data.chamelium,
-							   igt_kms_get_custom_edid(i));
-		}
-	}
-
-	igt_describe("DisplayPort tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-fast", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("dp-edid-read", DisplayPort) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_4K,
-					       ARRAY_SIZE(DP_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-non-4k",
-				  DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
-					       ARRAY_SIZE(DP_EDIDS_NON_4K));
-
-		igt_describe(igt_edid_resolution_list_desc);
-		connector_subtest("dp-edid-resolution-list", DisplayPort)
-			edid_resolution_list(&data, port);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-suspend", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("dp-hpd-storm", DisplayPort)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("dp-hpd-storm-disable", DisplayPort)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("dp-crc-fast", DisplayPort)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("dp-frame-dump", DisplayPort)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("dp-mode-timings", DisplayPort)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("dp-audio", DisplayPort)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("dp-audio-edid", DisplayPort)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("HDMI tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-fast", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("hdmi-edid-read", HDMIA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("hdmi-hpd-storm", HDMIA)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("hdmi-crc-fast", HDMIA)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CRC, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-crc-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CRC);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (!igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-cmp-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CHECKERBOARD);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("hdmi-frame-dump", HDMIA)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("hdmi-mode-timings", HDMIA)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("hdmi-audio", HDMIA)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("hdmi-audio-edid", HDMIA)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_aspect_ratio_desc);
-		connector_subtest("hdmi-aspect-ratio", HDMIA)
-			test_display_aspect_ratio(&data, port);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("VGA tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-fast", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-enable-disable-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-with-enabled-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("vga-edid-read", VGA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-suspend", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-hibernate", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_without_ddc_desc);
-		connector_subtest("vga-hpd-without-ddc", VGA)
-			test_hpd_without_ddc(&data, port);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("vga-frame-dump", VGA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_ANALOG, 1);
-	}
-
-	igt_describe("Tests that operate on all connectors");
-	igt_subtest_group {
-
-		igt_fixture {
-			igt_require(data.port_count);
-		}
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-suspend")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_MEM,
-						       SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-hibernate")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_DISK,
-						       SUSPEND_TEST_DEVICES);
-	}
-
-	igt_describe(test_hotplug_for_each_pipe_desc);
-	connector_subtest("vga-hpd-for-each-pipe", VGA)
-		test_hotplug_for_each_pipe(&data, port);
-
-	igt_fixture {
-		igt_display_fini(&data.display);
-		close(data.drm_fd);
-	}
-}
diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
new file mode 100644
index 00000000..4d13744c
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_audio.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the Audio functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+/* Playback parameters control the audio signal we synthesize and send */
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_SAMPLES 1024
+
+/* Capture paremeters control the audio signal we receive */
+#define CAPTURE_SAMPLES 2048
+
+#define AUDIO_TIMEOUT 2000 /* ms */
+/* A streak of 3 gives confidence that the signal is good. */
+#define MIN_STREAK 3
+
+#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
+#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
+#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
+
+struct audio_state {
+	struct alsa *alsa;
+	struct chamelium *chamelium;
+	struct chamelium_port *port;
+	struct chamelium_stream *stream;
+
+	/* The capture format is only available after capture has started. */
+	struct {
+		snd_pcm_format_t format;
+		int channels;
+		int rate;
+	} playback, capture;
+
+	char *name;
+	struct audio_signal *signal; /* for frequencies test only */
+	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	size_t recv_pages;
+	int msec;
+
+	int dump_fd;
+	char *dump_path;
+
+	pthread_t thread;
+	atomic_bool run;
+	atomic_bool positive; /* for pulse test only */
+};
+
+/* TODO: enable >48KHz rates, these are not reliable */
+static int test_sampling_rates[] = {
+	32000, 44100, 48000,
+	/* 88200, */
+	/* 96000, */
+	/* 176400, */
+	/* 192000, */
+};
+
+static int test_sampling_rates_count =
+	sizeof(test_sampling_rates) / sizeof(int);
+
+/* Test frequencies (Hz): a sine signal will be generated for each.
+ *
+ * Depending on the sampling rate chosen, it might not be possible to properly
+ * detect the generated sine (see Nyquist–Shannon sampling theorem).
+ * Frequencies that can't be reliably detected will be automatically pruned in
+ * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
+ * tested with a 192KHz sampling rate.
+ */
+static int test_frequencies[] = {
+	300, 600, 1200, 10000, 80000,
+};
+
+static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
+
+static const snd_pcm_format_t test_formats[] = {
+	SND_PCM_FORMAT_S16_LE,
+	SND_PCM_FORMAT_S24_LE,
+	SND_PCM_FORMAT_S32_LE,
+};
+
+static const size_t test_formats_count =
+	sizeof(test_formats) / sizeof(test_formats[0]);
+
+static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
+			     struct alsa *alsa, struct chamelium_port *port,
+			     snd_pcm_format_t format, int channels, int rate)
+{
+	memset(state, 0, sizeof(*state));
+	state->dump_fd = -1;
+
+	state->alsa = alsa;
+	state->chamelium = data->chamelium;
+	state->port = port;
+
+	state->playback.format = format;
+	state->playback.channels = channels;
+	state->playback.rate = rate;
+
+	alsa_configure_output(alsa, format, channels, rate);
+
+	state->stream = chamelium_stream_init();
+	igt_assert_f(state->stream,
+		     "Failed to initialize Chamelium stream client\n");
+}
+
+static void audio_state_fini(struct audio_state *state)
+{
+	chamelium_stream_deinit(state->stream);
+	free(state->name);
+}
+
+static void *run_audio_thread(void *data)
+{
+	struct alsa *alsa = data;
+
+	alsa_run(alsa, -1);
+	return NULL;
+}
+
+static void audio_state_start(struct audio_state *state, const char *name)
+{
+	int ret;
+	bool ok;
+	size_t i, j;
+	enum chamelium_stream_realtime_mode stream_mode;
+	char dump_suffix[64];
+
+	free(state->name);
+	state->name = strdup(name);
+	state->recv_pages = 0;
+	state->msec = 0;
+
+	igt_debug("Starting %s test with playback format %s, "
+		  "sampling rate %d Hz and %d channels\n",
+		  name, snd_pcm_format_name(state->playback.format),
+		  state->playback.rate, state->playback.channels);
+
+	chamelium_start_capturing_audio(state->chamelium, state->port, false);
+
+	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
+	igt_assert_f(ok, "Failed to start streaming audio capture\n");
+
+	/* Start playing audio */
+	state->run = true;
+	ret = pthread_create(&state->thread, NULL, run_audio_thread,
+			     state->alsa);
+	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
+
+	/* The Chamelium device only supports this PCM format. */
+	state->capture.format = SND_PCM_FORMAT_S32_LE;
+
+	/* Only after we've started playing audio, we can retrieve the capture
+	 * format used by the Chamelium device. */
+	chamelium_get_audio_format(state->chamelium, state->port,
+				   &state->capture.rate,
+				   &state->capture.channels);
+	if (state->capture.rate == 0) {
+		igt_debug("Audio receiver doesn't indicate the capture "
+			  "sampling rate, assuming it's %d Hz\n",
+			  state->playback.rate);
+		state->capture.rate = state->playback.rate;
+	}
+
+	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
+					    state->channel_mapping);
+	/* Make sure we can capture all channels we send. */
+	for (i = 0; i < state->playback.channels; i++) {
+		ok = false;
+		for (j = 0; j < state->capture.channels; j++) {
+			if (state->channel_mapping[j] == i) {
+				ok = true;
+				break;
+			}
+		}
+		igt_assert_f(ok, "Cannot capture all channels\n");
+	}
+
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix),
+			 "capture-%s-%s-%dch-%dHz", name,
+			 snd_pcm_format_name(state->playback.format),
+			 state->playback.channels, state->playback.rate);
+
+		state->dump_fd = audio_create_wav_file_s32_le(
+			dump_suffix, state->capture.rate,
+			state->capture.channels, &state->dump_path);
+		igt_assert_f(state->dump_fd >= 0,
+			     "Failed to create audio dump file\n");
+	}
+}
+
+static void audio_state_receive(struct audio_state *state, int32_t **recv,
+				size_t *recv_len)
+{
+	bool ok;
+	size_t page_count;
+	size_t recv_size;
+
+	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
+						     recv, recv_len);
+	igt_assert_f(ok, "Failed to receive audio from stream server\n");
+
+	state->msec = state->recv_pages * *recv_len /
+		      (double)state->capture.channels /
+		      (double)state->capture.rate * 1000;
+	state->recv_pages++;
+
+	if (state->dump_fd >= 0) {
+		recv_size = *recv_len * sizeof(int32_t);
+		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
+				     recv_size,
+			     "Failed to write to audio dump file\n");
+	}
+}
+
+static void audio_state_stop(struct audio_state *state, bool success)
+{
+	bool ok;
+	int ret;
+	struct chamelium_audio_file *audio_file;
+	enum igt_log_level log_level;
+
+	igt_debug("Stopping audio playback\n");
+	state->run = false;
+	ret = pthread_join(state->thread, NULL);
+	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
+
+	ok = chamelium_stream_stop_realtime_audio(state->stream);
+	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
+
+	audio_file =
+		chamelium_stop_capturing_audio(state->chamelium, state->port);
+	if (audio_file) {
+		igt_debug("Audio file saved on the Chamelium in %s\n",
+			  audio_file->path);
+		chamelium_destroy_audio_file(audio_file);
+	}
+
+	if (state->dump_fd >= 0) {
+		close(state->dump_fd);
+		state->dump_fd = -1;
+
+		if (success) {
+			/* Test succeeded, no need to keep the captured data */
+			unlink(state->dump_path);
+		} else
+			igt_debug("Saved captured audio data to %s\n",
+				  state->dump_path);
+		free(state->dump_path);
+		state->dump_path = NULL;
+	}
+
+	if (success)
+		log_level = IGT_LOG_DEBUG;
+	else
+		log_level = IGT_LOG_CRITICAL;
+
+	igt_log(IGT_LOG_DOMAIN, log_level,
+		"Audio %s test result for format %s, "
+		"sampling rate %d Hz and %d channels: %s\n",
+		state->name, snd_pcm_format_name(state->playback.format),
+		state->playback.rate, state->playback.channels,
+		success ? "ALL GREEN" : "FAILED");
+}
+
+static void check_audio_infoframe(struct audio_state *state)
+{
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_audio infoframe_audio;
+	struct infoframe_audio expected = { 0 };
+	bool ok;
+
+	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
+		igt_debug("Skipping audio InfoFrame check: "
+			  "Chamelium board doesn't support GetLastInfoFrame\n");
+		return;
+	}
+
+	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
+	expected.channel_count = state->playback.channels;
+	expected.sampling_freq = state->playback.rate;
+	expected.sample_size = snd_pcm_format_width(state->playback.format);
+
+	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
+						 CHAMELIUM_INFOFRAME_AUDIO);
+	if (infoframe == NULL && state->playback.channels <= 2) {
+		/* Audio InfoFrames are optional for mono and stereo audio */
+		igt_debug("Skipping audio InfoFrame check: "
+			  "no InfoFrame received\n");
+		return;
+	}
+	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
+
+	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
+				   infoframe->payload, infoframe->payload_size);
+	chamelium_infoframe_destroy(infoframe);
+	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
+
+	igt_debug("Checking audio InfoFrame:\n");
+	igt_debug("coding_type: got %d, expected %d\n",
+		  infoframe_audio.coding_type, expected.coding_type);
+	igt_debug("channel_count: got %d, expected %d\n",
+		  infoframe_audio.channel_count, expected.channel_count);
+	igt_debug("sampling_freq: got %d, expected %d\n",
+		  infoframe_audio.sampling_freq, expected.sampling_freq);
+	igt_debug("sample_size: got %d, expected %d\n",
+		  infoframe_audio.sample_size, expected.sample_size);
+
+	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
+		igt_assert(infoframe_audio.coding_type == expected.coding_type);
+	if (infoframe_audio.channel_count >= 0)
+		igt_assert(infoframe_audio.channel_count ==
+			   expected.channel_count);
+	if (infoframe_audio.sampling_freq >= 0)
+		igt_assert(infoframe_audio.sampling_freq ==
+			   expected.sampling_freq);
+	if (infoframe_audio.sample_size >= 0)
+		igt_assert(infoframe_audio.sample_size == expected.sample_size);
+}
+
+static int audio_output_frequencies_callback(void *data, void *buffer,
+					     int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	audio_signal_fill(state->signal, tmp, samples);
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool test_audio_frequencies(struct audio_state *state)
+{
+	int freq, step;
+	int32_t *recv, *buf;
+	double *channel;
+	size_t i, j, streak;
+	size_t recv_len, buf_len, buf_cap, channel_len;
+	bool success;
+	int capture_chan;
+
+	state->signal = audio_signal_init(state->playback.channels,
+					  state->playback.rate);
+	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
+
+	/* We'll choose different frequencies per channel to make sure they are
+	 * independent from each other. To do so, we'll add a different offset
+	 * to the base frequencies for each channel. We need to choose a big
+	 * enough offset so that we're sure to detect mixed up channels. We
+	 * choose an offset of two 2 bins in the final FFT to enforce a clear
+	 * difference.
+	 *
+	 * Note that we assume capture_rate == playback_rate. We'll assert this
+	 * later on. We cannot retrieve the capture rate before starting
+	 * playing audio, so we don't really have the choice.
+	 */
+	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
+	for (i = 0; i < test_frequencies_count; i++) {
+		for (j = 0; j < state->playback.channels; j++) {
+			freq = test_frequencies[i] + j * step;
+			audio_signal_add_frequency(state->signal, freq, j);
+		}
+	}
+	audio_signal_synthesize(state->signal);
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_frequencies_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	audio_state_start(state, "frequencies");
+
+	igt_assert_f(state->capture.rate == state->playback.rate,
+		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
+		     state->capture.rate, state->playback.rate);
+
+	/* Needs to be a multiple of 128, because that's the number of samples
+	 * we get per channel each time we receive an audio page from the
+	 * Chamelium device.
+	 *
+	 * Additionally, this value needs to be high enough to guarantee we
+	 * capture a full period of each sine we generate. If we capture 2048
+	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
+	 * sines. For lower sampling rates, the capture duration will be
+	 * longer.
+	 */
+	channel_len = CAPTURE_SAMPLES;
+	channel = malloc(sizeof(double) * channel_len);
+
+	buf_cap = state->capture.channels * channel_len;
+	buf = malloc(sizeof(int32_t) * buf_cap);
+	buf_len = 0;
+
+	recv = NULL;
+	recv_len = 0;
+
+	success = false;
+	streak = 0;
+	while (!success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
+		buf_len += recv_len;
+
+		if (buf_len < buf_cap)
+			continue;
+		igt_assert(buf_len == buf_cap);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (j = 0; j < state->playback.channels; j++) {
+			capture_chan = state->channel_mapping[j];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  j, capture_chan);
+
+			audio_extract_channel_s32_le(channel, channel_len, buf,
+						     buf_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			if (audio_signal_detect(state->signal,
+						state->capture.rate, j, channel,
+						channel_len))
+				streak++;
+			else
+				streak = 0;
+		}
+
+		buf_len = 0;
+
+		success = streak == MIN_STREAK * state->playback.channels;
+	}
+
+	audio_state_stop(state, success);
+
+	free(recv);
+	free(buf);
+	free(channel);
+	audio_signal_fini(state->signal);
+
+	check_audio_infoframe(state);
+
+	return success;
+}
+
+static int audio_output_flatline_callback(void *data, void *buffer, int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len, i;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	for (i = 0; i < len; i++)
+		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
+{
+	double expected, min, max;
+	size_t i;
+	bool ok;
+
+	min = max = NAN;
+	for (i = 0; i < buf_len; i++) {
+		if (isnan(min) || buf[i] < min)
+			min = buf[i];
+		if (isnan(max) || buf[i] > max)
+			max = buf[i];
+	}
+
+	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
+	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
+	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
+	if (ok)
+		igt_debug("Flatline wave amplitude detected\n");
+	else
+		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
+			  min, max);
+	return ok;
+}
+
+static ssize_t detect_falling_edge(double *buf, size_t buf_len)
+{
+	size_t i;
+
+	for (i = 0; i < buf_len; i++) {
+		if (buf[i] < 0)
+			return i;
+	}
+
+	return -1;
+}
+
+/** test_audio_flatline:
+ *
+ * Send a constant value (one positive, then a negative one) and check that:
+ *
+ * - The amplitude of the flatline is correct
+ * - All channels switch from a positive signal to a negative one at the same
+ *   time (ie. all channels are aligned)
+ */
+static bool test_audio_flatline(struct audio_state *state)
+{
+	bool success, amp_success, align_success;
+	int32_t *recv;
+	size_t recv_len, i, channel_len;
+	ssize_t j;
+	int streak, capture_chan;
+	double *channel;
+	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_flatline_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	/* Start by sending a positive signal */
+	state->positive = true;
+
+	audio_state_start(state, "flatline");
+
+	for (i = 0; i < state->playback.channels; i++)
+		falling_edges[i] = -1;
+
+	recv = NULL;
+	recv_len = 0;
+	amp_success = false;
+	streak = 0;
+	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (i = 0; i < state->playback.channels; i++) {
+			capture_chan = state->channel_mapping[i];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  i, capture_chan);
+
+			channel_len = audio_extract_channel_s32_le(
+				NULL, 0, recv, recv_len,
+				state->capture.channels, capture_chan);
+			channel = malloc(channel_len * sizeof(double));
+			audio_extract_channel_s32_le(channel, channel_len, recv,
+						     recv_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			/* Check whether the amplitude is fine */
+			if (detect_flatline_amplitude(channel, channel_len,
+						      state->positive))
+				streak++;
+			else
+				streak = 0;
+
+			/* If we're now sending a negative signal, detect the
+			 * falling edge */
+			j = detect_falling_edge(channel, channel_len);
+			if (!state->positive && j >= 0) {
+				falling_edges[i] =
+					recv_len * state->recv_pages + j;
+			}
+
+			free(channel);
+		}
+
+		amp_success = streak == MIN_STREAK * state->playback.channels;
+
+		if (amp_success && state->positive) {
+			/* Switch to a negative signal after we've detected the
+			 * positive one. */
+			state->positive = false;
+			amp_success = false;
+			streak = 0;
+			igt_debug("Switching to negative square wave\n");
+		}
+	}
+
+	/* Check alignment between all channels by comparing the index of the
+	 * falling edge. */
+	align_success = true;
+	for (i = 0; i < state->playback.channels; i++) {
+		if (falling_edges[i] < 0) {
+			igt_critical(
+				"Falling edge not detected for channel %zu\n",
+				i);
+			align_success = false;
+			continue;
+		}
+
+		if (abs(falling_edges[0] - falling_edges[i]) >
+		    FLATLINE_ALIGN_ACCURACY) {
+			igt_critical("Channel alignment mismatch: "
+				     "channel 0 has a falling edge at index %d "
+				     "while channel %zu has index %d\n",
+				     falling_edges[0], i, falling_edges[i]);
+			align_success = false;
+		}
+	}
+
+	success = amp_success && align_success;
+	audio_state_stop(state, success);
+
+	free(recv);
+
+	return success;
+}
+
+static bool check_audio_configuration(struct alsa *alsa,
+				      snd_pcm_format_t format, int channels,
+				      int sampling_rate)
+{
+	if (!alsa_test_output_configuration(alsa, format, channels,
+					    sampling_rate)) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because at least one of the "
+			  "selected output devices doesn't support this "
+			  "configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	/* TODO: the Chamelium device sends a malformed signal for some audio
+	 * configurations. See crbug.com/950917 */
+	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
+	    channels > 2) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because the Chamelium device "
+			  "doesn't support this configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	return true;
+}
+
+static const char test_display_audio_desc[] =
+	"Playback various audio signals with various audio formats/rates, "
+	"capture them and check they are correct";
+static void test_display_audio(chamelium_data_t *data,
+			       struct chamelium_port *port,
+			       const char *audio_device,
+			       enum igt_custom_edid_type edid)
+{
+	bool run, success;
+	struct alsa *alsa;
+	int ret;
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id, i, j;
+	int channels, sampling_rate;
+	snd_pcm_format_t format;
+	struct audio_state state;
+
+	igt_require(alsa_has_exclusive_access());
+
+	/* Old Chamelium devices need an update for DisplayPort audio and
+	 * chamelium_get_audio_format support. */
+	igt_require(chamelium_has_audio_support(data->chamelium, port));
+
+	alsa = alsa_init();
+	igt_assert(alsa);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because the receiver won't try to receive audio if
+	 * it doesn't receive video. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	run = false;
+	success = true;
+	for (i = 0; i < test_sampling_rates_count; i++) {
+		for (j = 0; j < test_formats_count; j++) {
+			ret = alsa_open_output(alsa, audio_device);
+			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
+
+			/* TODO: playback on all 8 available channels (this
+			 * isn't supported by Chamelium devices yet, see
+			 * https://crbug.com/950917) */
+			format = test_formats[j];
+			channels = PLAYBACK_CHANNELS;
+			sampling_rate = test_sampling_rates[i];
+
+			if (!check_audio_configuration(alsa, format, channels,
+						       sampling_rate))
+				continue;
+
+			run = true;
+
+			audio_state_init(&state, data, alsa, port, format,
+					 channels, sampling_rate);
+			success &= test_audio_frequencies(&state);
+			success &= test_audio_flatline(&state);
+			audio_state_fini(&state);
+
+			alsa_close_output(alsa);
+		}
+	}
+
+	/* Make sure we tested at least one frequency and format. */
+	igt_assert(run);
+	/* Make sure all runs were successful. */
+	igt_assert(success);
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+
+	free(alsa);
+}
+
+static const char test_display_audio_edid_desc[] =
+	"Plug a connector with an EDID suitable for audio, check ALSA's "
+	"EDID-Like Data reports the correct audio parameters";
+static void test_display_audio_edid(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_custom_edid_type edid)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id;
+	struct eld_entry eld;
+	struct eld_sad *sad;
+
+	igt_require(eld_is_supported());
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because audio cannot be played on inactive
+	 * connectors. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	igt_assert(eld_get_igt(&eld));
+	igt_assert(eld.sads_len == 1);
+
+	sad = &eld.sads[0];
+	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
+	igt_assert(sad->channels == 2);
+	igt_assert(sad->rates ==
+		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
+		    CEA_SAD_SAMPLING_RATE_48KHZ));
+	igt_assert(sad->bits ==
+		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
+		    CEA_SAD_SAMPLE_SIZE_24));
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+}
+
+IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("dp-audio", DisplayPort) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("dp-audio-edid", DisplayPort)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_DP_AUDIO);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("hdmi-audio-edid", HDMIA)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_HDMI_AUDIO);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
similarity index 100%
rename from tests/chamelium/kms_color_chamelium.c
rename to tests/chamelium/kms_chamelium_color.c
diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
new file mode 100644
index 00000000..36ec5f02
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_edid.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the EDID functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include <xf86drmMode.h>
+
+#include "igt_chamelium.h"
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+#include "monitor_edids/dp_edids.h"
+#include "monitor_edids/hdmi_edids.h"
+#include "monitor_edids/monitor_edids_helper.h"
+
+#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
+
+static void get_connectors_link_status_failed(chamelium_data_t *data,
+					      bool *link_status_failed)
+{
+	drmModeConnector *connector;
+	uint64_t link_status;
+	drmModePropertyPtr prop;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		connector = chamelium_port_get_connector(data->chamelium,
+							 data->ports[p], false);
+
+		igt_assert(kmstest_get_property(
+			data->drm_fd, connector->connector_id,
+			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
+			&link_status, &prop));
+
+		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
+
+		drmModeFreeProperty(prop);
+		drmModeFreeConnector(connector);
+	}
+}
+
+static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
+		       drmModeModeInfo *mode)
+{
+	struct chamelium_video_params video_params = { 0 };
+	double mode_clock;
+	int mode_hsync_offset, mode_vsync_offset;
+	int mode_hsync_width, mode_vsync_width;
+	int mode_hsync_polarity, mode_vsync_polarity;
+
+	chamelium_port_get_video_params(chamelium, port, &video_params);
+
+	mode_clock = (double)mode->clock / 1000;
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
+		/* this is what chamelium understands as offsets for DP */
+		mode_hsync_offset = mode->htotal - mode->hsync_start;
+		mode_vsync_offset = mode->vtotal - mode->vsync_start;
+	} else {
+		/* and this is what they are for other connectors */
+		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
+		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
+	}
+
+	mode_hsync_width = mode->hsync_end - mode->hsync_start;
+	mode_vsync_width = mode->vsync_end - mode->vsync_start;
+
+	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	igt_debug("Checking video mode:\n");
+	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
+		  mode_clock, MODE_CLOCK_ACCURACY * 100);
+	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
+		  mode->hdisplay);
+	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
+		  mode->vdisplay);
+	igt_debug("hsync_offset: got %d, expected %d\n",
+		  video_params.hsync_offset, mode_hsync_offset);
+	igt_debug("vsync_offset: got %d, expected %d\n",
+		  video_params.vsync_offset, mode_vsync_offset);
+	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
+		  mode->htotal);
+	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
+		  mode->vtotal);
+	igt_debug("hsync_width: got %d, expected %d\n",
+		  video_params.hsync_width, mode_hsync_width);
+	igt_debug("vsync_width: got %d, expected %d\n",
+		  video_params.vsync_width, mode_vsync_width);
+	igt_debug("hsync_polarity: got %d, expected %d\n",
+		  video_params.hsync_polarity, mode_hsync_polarity);
+	igt_debug("vsync_polarity: got %d, expected %d\n",
+		  video_params.vsync_polarity, mode_vsync_polarity);
+
+	if (!isnan(video_params.clock)) {
+		igt_assert(video_params.clock >
+			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
+		igt_assert(video_params.clock <
+			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
+	}
+	igt_assert(video_params.hactive == mode->hdisplay);
+	igt_assert(video_params.vactive == mode->vdisplay);
+	igt_assert(video_params.hsync_offset == mode_hsync_offset);
+	igt_assert(video_params.vsync_offset == mode_vsync_offset);
+	igt_assert(video_params.htotal == mode->htotal);
+	igt_assert(video_params.vtotal == mode->vtotal);
+	igt_assert(video_params.hsync_width == mode_hsync_width);
+	igt_assert(video_params.vsync_width == mode_vsync_width);
+	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
+	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
+}
+
+static const char igt_custom_edid_type_read_desc[] =
+	"Make sure the EDID exposed by KMS is the same as the screen's";
+static void igt_custom_edid_type_read(chamelium_data_t *data,
+				      struct chamelium_port *port,
+				      enum igt_custom_edid_type edid)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector;
+	size_t raw_edid_size;
+	const struct edid *raw_edid;
+	uint64_t edid_blob_id;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_skip_on(chamelium_check_analog_bridge(data, port));
+
+	connector = chamelium_port_get_connector(data->chamelium, port, true);
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob_id != 0);
+	edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
+	igt_assert(edid_blob);
+
+	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
+	raw_edid_size = edid_get_size(raw_edid);
+	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+}
+
+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(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   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;
+
+		monitor_edid *edid = &edids_list[i];
+		igt_info("Testing out the EDID for %s\n",
+			 monitor_edid_get_name(edid));
+
+		/* Getting and Setting the EDID on Chamelium. */
+		chamelium_edid =
+			get_chameleon_edid_from_monitor_edid(chamelium, 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);
+		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
+		chamelium_create_fb_for_mode(data, &fb, &mode);
+		output = chamelium_get_output_for_port(data, port);
+		pipe = chamelium_get_pipe_for_output(&data->display, output);
+		igt_output_set_pipe(output, pipe);
+		chamelium_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);
+}
+
+static const char igt_edid_resolution_list_desc[] =
+	"Get an EDID with many modes of different configurations, set them on the screen and check the"
+	" screen resolution matches the mode resolution.";
+
+static void edid_resolution_list(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct chamelium *chamelium = data->chamelium;
+	struct udev_monitor *mon = igt_watch_uevents();
+	drmModeConnector *connector;
+	drmModeModeInfoPtr modes;
+	int count_modes;
+	int i;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	chamelium_unplug(chamelium, port);
+	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
+
+	igt_flush_uevents(mon);
+	chamelium_plug(chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_CONNECTED);
+	igt_flush_uevents(mon);
+
+	connector = chamelium_port_get_connector(chamelium, port, true);
+	modes = connector->modes;
+	count_modes = connector->count_modes;
+
+	output = chamelium_get_output_for_port(data, port);
+	pipe = chamelium_get_pipe_for_output(&data->display, output);
+	igt_output_set_pipe(output, pipe);
+
+	for (i = 0; i < count_modes; ++i)
+		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
+
+	for (i = 0; i < count_modes; ++i) {
+		struct igt_fb fb = { 0 };
+		bool is_video_stable;
+		int screen_res_w, screen_res_h;
+
+		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
+			 modes[i].vrefresh);
+
+		/* Set the screen mode with the one we chose. */
+		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
+		chamelium_enable_output(data, port, output, &modes[i], &fb);
+		is_video_stable = chamelium_port_wait_video_input_stable(
+			chamelium, port, 10);
+		igt_assert(is_video_stable);
+
+		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
+					      &screen_res_h);
+		igt_assert_eq(screen_res_w, modes[i].hdisplay);
+		igt_assert_eq(screen_res_h, modes[i].vdisplay);
+
+		igt_remove_fb(data->drm_fd, &fb);
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_suspend_resume_edid_change_desc[] =
+	"Simulate a screen being unplugged and another screen being plugged "
+	"during suspend, check that a uevent is sent and connector status is "
+	"updated";
+static void test_suspend_resume_edid_change(chamelium_data_t *data,
+					    struct chamelium_port *port,
+					    enum igt_suspend_state state,
+					    enum igt_suspend_test test,
+					    enum igt_custom_edid_type edid,
+					    enum igt_custom_edid_type alt_edid)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	bool link_status_failed[2][data->port_count];
+	int p;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Catch the event and flush all remaining ones. */
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_flush_uevents(mon);
+
+	/* First plug in the port */
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	/*
+	 * Change the edid before we suspend. On resume, the machine should
+	 * notice the EDID change and fire a hotplug event.
+	 */
+	chamelium_set_edid(data, port, alt_edid);
+
+	get_connectors_link_status_failed(data, link_status_failed[0]);
+
+	igt_flush_uevents(mon);
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	get_connectors_link_status_failed(data, link_status_failed[1]);
+
+	for (p = 0; p < data->port_count; p++)
+		igt_skip_on(!link_status_failed[0][p] &&
+			    link_status_failed[1][p]);
+}
+
+static const char test_mode_timings_desc[] =
+	"For each mode of the IGT base EDID, perform a modeset and check the "
+	"mode detected by the Chamelium receiver matches the mode we set";
+static void test_mode_timings(chamelium_data_t *data,
+			      struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	igt_require(chamelium_supports_get_video_params(data->chamelium));
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+		int fb_id;
+		struct igt_fb fb;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		/* Trigger the FSM */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
+
+		check_mode(data->chamelium, port, mode);
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("dp-edid-read", DisplayPort)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_4K,
+					       ARRAY_SIZE(DP_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-non-4k",
+				  DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
+					       ARRAY_SIZE(DP_EDIDS_NON_4K));
+
+		igt_describe(igt_edid_resolution_list_desc);
+		connector_subtest("dp-edid-resolution-list", DisplayPort)
+			edid_resolution_list(&data, port);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-hibernate",
+				  DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("dp-mode-timings", DisplayPort)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("hdmi-edid-read", HDMIA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("hdmi-mode-timings", HDMIA)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("vga-edid-read", VGA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
new file mode 100644
index 00000000..008bc34b
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_frames.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Lyude Paul <lyude@redhat.com>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+#define connector_dynamic_subtest(name__, type__)                   \
+	igt_subtest_with_dynamic(name__)                            \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+struct vic_mode {
+	int hactive, vactive;
+	int vrefresh; /* Hz */
+	uint32_t picture_ar;
+};
+
+static int chamelium_vga_modes[][2] = {
+	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
+	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
+	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
+	{ 640, 480 },	{ -1, -1 },
+};
+
+/* Maps Video Identification Codes to a mode */
+static const struct vic_mode vic_modes[] = {
+	[16] = {
+		.hactive = 1920,
+		.vactive = 1080,
+		.vrefresh = 60,
+		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
+	},
+};
+
+/* Maps aspect ratios to their mode flag */
+static const uint32_t mode_ar_flags[] = {
+	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
+};
+
+static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
+{
+	int i = 0;
+
+	while (chamelium_vga_modes[i][0] != -1) {
+		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
+		    mode->vdisplay == chamelium_vga_modes[i][1])
+			return false;
+
+		i++;
+	}
+
+	return true;
+}
+
+static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
+			    igt_output_t *output, drmModeModeInfo *mode,
+			    uint32_t fourcc, enum chamelium_check check,
+			    int count)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+	struct igt_fb frame_fb, fb;
+	int i, fb_id, captured_frame_count;
+	int frame_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &fb);
+	igt_assert(fb_id > 0);
+
+	frame_id =
+		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
+	igt_assert(frame_id > 0);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
+
+	chamelium_enable_output(data, port, output, mode, &frame_fb);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		igt_crc_t *expected_crc;
+		igt_crc_t *crc;
+
+		/* We want to keep the display running for a little bit, since
+		 * there's always the potential the driver isn't able to keep
+		 * the display running properly for very long
+		 */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == count);
+
+		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		for (i = 0; i < captured_frame_count; i++)
+			chamelium_assert_crc_eq_or_dump(
+				data->chamelium, expected_crc, &crc[i], &fb, i);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_ANALOG ||
+		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		igt_assert(count == 1);
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+
+		if (check == CHAMELIUM_CHECK_ANALOG)
+			chamelium_crop_analog_frame(dump, mode->hdisplay,
+						    mode->vdisplay);
+
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	igt_remove_fb(data->drm_fd, &frame_fb);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static enum infoframe_avi_picture_aspect_ratio
+get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
+{
+	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
+	switch (aspect_ratio) {
+	case DRM_MODE_PICTURE_ASPECT_4_3:
+		return INFOFRAME_AVI_PIC_AR_4_3;
+	case DRM_MODE_PICTURE_ASPECT_16_9:
+		return INFOFRAME_AVI_PIC_AR_16_9;
+	default:
+		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
+	}
+}
+
+static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
+				 drmModeModeInfo *drm_mode)
+{
+	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
+
+	return vic_mode->hactive == drm_mode->hdisplay &&
+	       vic_mode->vactive == drm_mode->vdisplay &&
+	       vic_mode->vrefresh == drm_mode->vrefresh &&
+	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
+}
+
+static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
+				   uint32_t height, uint32_t format,
+				   uint64_t modifier, size_t *stride)
+{
+	size_t stride_min;
+	uint32_t max_tile_w = 4, tile_w, tile_h;
+	int i;
+	struct igt_fb dummy;
+
+	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
+
+	/* Randomize the stride to less than twice the minimum. */
+	*stride = (rand() % stride_min) + stride_min;
+
+	/*
+	 * Create a dummy FB to determine bpp for each plane, and calculate
+	 * the maximum tile width from that.
+	 */
+	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
+	for (i = 0; i < dummy.num_planes; i++) {
+		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
+				     &tile_w, &tile_h);
+
+		if (tile_w > max_tile_w)
+			max_tile_w = tile_w;
+	}
+	igt_remove_fb(data->drm_fd, &dummy);
+
+	/*
+	 * Pixman requires the stride to be aligned to 32-bits, which is
+	 * reflected in the initial value of max_tile_w and the hw
+	 * may require a multiple of tile width, choose biggest of the 2.
+	 */
+	*stride = ALIGN(*stride, max_tile_w);
+}
+
+static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
+				  uint32_t height, uint32_t format,
+				  uint64_t *modifier)
+{
+	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
+		/* Randomize the column height to less than twice the minimum.
+		 */
+		size_t column_height = (rand() % height) + height;
+
+		igt_debug(
+			"Selecting VC4 SAND256 tiling with column height %ld\n",
+			column_height);
+
+		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
+			column_height);
+	}
+}
+
+static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
+				  drmModeModeInfo *mode, uint32_t *width,
+				  uint32_t *height, uint32_t *format,
+				  uint64_t *modifier, bool allow_yuv)
+{
+	int min_dim;
+	uint32_t idx[plane->format_mod_count];
+	unsigned int count = 0;
+	unsigned int i;
+
+	/* First pass to count the supported formats. */
+	for (i = 0; i < plane->format_mod_count; i++)
+		if (igt_fb_supported_format(plane->formats[i]) &&
+		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
+			idx[count++] = i;
+
+	igt_assert(count > 0);
+
+	i = idx[rand() % count];
+	*format = plane->formats[i];
+	*modifier = plane->modifiers[i];
+
+	update_tiled_modifier(plane, *width, *height, *format, modifier);
+
+	/*
+	 * Randomize width and height in the mode dimensions range.
+	 *
+	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
+	 * least min_dim, because src_w = width - (rand % w / 2).
+	 *
+	 * Use a minimum dimension of 16 for YUV, because planar YUV
+	 * subsamples the UV plane.
+	 */
+	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
+
+	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
+	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
+}
+
+static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
+			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
+			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
+			    struct igt_fb *fb)
+{
+	igt_plane_set_fb(plane, fb);
+
+	igt_plane_set_position(plane, crtc_x, crtc_y);
+	igt_plane_set_size(plane, crtc_w, crtc_h);
+
+	igt_fb_set_position(fb, plane, src_x, src_y);
+	igt_fb_set_size(fb, plane, src_w, src_h);
+}
+
+static void randomize_plane_coordinates(
+	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
+	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
+	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
+	int32_t *crtc_y, bool allow_scaling)
+{
+	bool is_yuv = igt_format_is_yuv(fb->drm_format);
+	uint32_t width = fb->width, height = fb->height;
+	double ratio;
+	int ret;
+
+	/* Randomize source offset in the first half of the original size. */
+	*src_x = rand() % (width / 2);
+	*src_y = rand() % (height / 2);
+
+	/* The source size only includes the active source area. */
+	*src_w = width - *src_x;
+	*src_h = height - *src_y;
+
+	if (allow_scaling) {
+		*crtc_w = (rand() % mode->hdisplay) + 1;
+		*crtc_h = (rand() % mode->vdisplay) + 1;
+
+		/*
+		 * Don't bother with scaling if dimensions are quite close in
+		 * order to get non-scaling cases more frequently. Also limit
+		 * scaling to 3x to avoid aggressive filtering that makes
+		 * comparison less reliable, and don't go above 2x downsampling
+		 * to avoid possible hw limitations.
+		 */
+
+		ratio = ((double)*crtc_w / *src_w);
+		if (ratio < 0.5)
+			*src_w = *crtc_w * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_w = *src_w;
+		else if (ratio > 3.0)
+			*crtc_w = *src_w * 3;
+
+		ratio = ((double)*crtc_h / *src_h);
+		if (ratio < 0.5)
+			*src_h = *crtc_h * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_h = *src_h;
+		else if (ratio > 3.0)
+			*crtc_h = *src_h * 3;
+	} else {
+		*crtc_w = *src_w;
+		*crtc_h = *src_h;
+	}
+
+	if (*crtc_w != *src_w || *crtc_h != *src_h) {
+		/*
+		 * When scaling is involved, make sure to not go off-bounds or
+		 * scaled clipping may result in decimal dimensions, that most
+		 * drivers don't support.
+		 */
+		if (*crtc_w < mode->hdisplay)
+			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
+		else
+			*crtc_x = 0;
+
+		if (*crtc_h < mode->vdisplay)
+			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
+		else
+			*crtc_y = 0;
+	} else {
+		/*
+		 * Randomize the on-crtc position and allow the plane to go
+		 * off-display by less than half of its on-crtc dimensions.
+		 */
+		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
+		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
+	}
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	ret = igt_display_try_commit_atomic(
+		&data->display,
+		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
+		NULL);
+	if (!ret)
+		return;
+
+	/* Coordinates are logged in the dumped debug log, so only report w/h on
+	 * failure here. */
+	igt_assert_f(ret != -ENOSPC,
+		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
+		     width, height);
+
+	/* Make YUV coordinates a multiple of 2 and retry the math. */
+	if (is_yuv) {
+		*src_x &= ~1;
+		*src_y &= ~1;
+		*src_w &= ~1;
+		*src_h &= ~1;
+		/* To handle 1:1 scaling, clear crtc_w/h too. */
+		*crtc_w &= ~1;
+		*crtc_h &= ~1;
+
+		if (*crtc_x < 0 && (*crtc_x & 1))
+			(*crtc_x)++;
+		else
+			*crtc_x &= ~1;
+
+		/* If negative, round up to 0 instead of down */
+		if (*crtc_y < 0 && (*crtc_y & 1))
+			(*crtc_y)++;
+		else
+			*crtc_y &= ~1;
+
+		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
+				*crtc_h, *crtc_x, *crtc_y, fb);
+		ret = igt_display_try_commit_atomic(
+			&data->display,
+			DRM_MODE_ATOMIC_TEST_ONLY |
+				DRM_MODE_ATOMIC_ALLOW_MODESET,
+			NULL);
+		if (!ret)
+			return;
+	}
+
+	igt_assert(!ret || allow_scaling);
+	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
+		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
+
+	*crtc_w = *src_w;
+	*crtc_h = *src_h;
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	igt_display_commit_atomic(&data->display,
+				  DRM_MODE_ATOMIC_TEST_ONLY |
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+				  NULL);
+}
+
+static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
+			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
+			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
+			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
+{
+	cairo_surface_t *surface;
+	cairo_surface_t *clipped_surface;
+	cairo_t *cr;
+
+	surface = igt_get_cairo_surface(data->drm_fd, fb);
+
+	if (src_x || src_y) {
+		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+							     src_w, src_h);
+
+		cr = cairo_create(clipped_surface);
+
+		cairo_translate(cr, -1. * src_x, -1. * src_y);
+
+		cairo_set_source_surface(cr, surface, 0, 0);
+
+		cairo_paint(cr);
+		cairo_surface_flush(clipped_surface);
+
+		cairo_destroy(cr);
+	} else {
+		clipped_surface = surface;
+	}
+
+	cr = cairo_create(result);
+
+	cairo_translate(cr, crtc_x, crtc_y);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
+	}
+
+	cairo_set_source_surface(cr, clipped_surface, 0, 0);
+	cairo_surface_destroy(clipped_surface);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_pattern_set_filter(cairo_get_source(cr),
+					 CAIRO_FILTER_BILINEAR);
+		cairo_pattern_set_extend(cairo_get_source(cr),
+					 CAIRO_EXTEND_NONE);
+	}
+
+	cairo_paint(cr);
+	cairo_surface_flush(result);
+
+	cairo_destroy(cr);
+}
+
+static void prepare_randomized_plane(chamelium_data_t *data,
+				     drmModeModeInfo *mode, igt_plane_t *plane,
+				     struct igt_fb *overlay_fb,
+				     unsigned int index,
+				     cairo_surface_t *result_surface,
+				     bool allow_scaling, bool allow_yuv)
+{
+	struct igt_fb pattern_fb;
+	uint32_t overlay_fb_w, overlay_fb_h;
+	uint32_t overlay_src_w, overlay_src_h;
+	uint32_t overlay_src_x, overlay_src_y;
+	int32_t overlay_crtc_x, overlay_crtc_y;
+	uint32_t overlay_crtc_w, overlay_crtc_h;
+	uint32_t format;
+	uint64_t modifier;
+	size_t stride;
+	bool tiled;
+	int fb_id;
+
+	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
+			      &format, &modifier, allow_yuv);
+
+	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
+	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
+		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
+		  tiled ? "tiled" : "linear");
+
+	/* Get a pattern framebuffer for the overlay plane. */
+	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
+					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
+			       modifier, &stride);
+
+	igt_debug("Plane %d: stride %ld\n", index, stride);
+
+	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
+					   modifier, stride);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_coordinates(data, plane, mode, overlay_fb,
+				    &overlay_src_w, &overlay_src_h,
+				    &overlay_src_x, &overlay_src_y,
+				    &overlay_crtc_w, &overlay_crtc_h,
+				    &overlay_crtc_x, &overlay_crtc_y,
+				    allow_scaling);
+
+	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
+		  overlay_src_h);
+	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
+		  overlay_src_x, overlay_src_y);
+	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
+		  overlay_crtc_h);
+	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
+		  overlay_crtc_y);
+
+	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
+			 overlay_src_x, overlay_src_y, overlay_crtc_w,
+			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
+			 &pattern_fb);
+
+	/* Remove the original pattern framebuffer. */
+	igt_remove_fb(data->drm_fd, &pattern_fb);
+}
+
+static const char test_display_one_mode_desc[] =
+	"Pick the first mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_one_mode(chamelium_data_t *data,
+				  struct chamelium_port *port, uint32_t fourcc,
+				  enum chamelium_check check, int count)
+{
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	igt_output_t *output;
+	igt_plane_t *primary;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	igt_require(igt_plane_has_format_mod(primary, fourcc,
+					     DRM_FORMAT_MOD_LINEAR));
+
+	mode = &connector->modes[0];
+	if (check == CHAMELIUM_CHECK_ANALOG) {
+		bool bridge = chamelium_check_analog_bridge(data, port);
+
+		igt_assert(!(bridge && prune_vga_mode(data, mode)));
+	}
+
+	do_test_display(data, port, output, mode, fourcc, check, count);
+
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_all_modes_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_all_modes(chamelium_data_t *data,
+				   struct chamelium_port *port, uint32_t fourcc,
+				   enum chamelium_check check, int count)
+{
+	bool bridge;
+	int i, count_modes;
+
+	if (check == CHAMELIUM_CHECK_ANALOG)
+		bridge = chamelium_check_analog_bridge(data, port);
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+		igt_require(igt_plane_has_format_mod(primary, fourcc,
+						     DRM_FORMAT_MOD_LINEAR));
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
+		    prune_vga_mode(data, mode))
+			continue;
+
+		do_test_display(data, port, output, mode, fourcc, check, count);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_frame_dump_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then download the captured frames and compare them "
+	"bit-by-bit to the sent ones";
+static void test_display_frame_dump(chamelium_data_t *data,
+				    struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		struct igt_fb fb;
+		struct chamelium_frame_dump *frame;
+		drmModeModeInfo *mode;
+		drmModeConnector *connector;
+		int fb_id, j;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		igt_debug("Reading frame dumps from Chamelium...\n");
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
+		for (j = 0; j < 5; j++) {
+			frame = chamelium_read_captured_frame(data->chamelium,
+							      j);
+			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
+			chamelium_destroy_frame_dump(frame);
+		}
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_aspect_ratio_desc[] =
+	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
+	"check they include the relevant fields";
+static void test_display_aspect_ratio(chamelium_data_t *data,
+				      struct chamelium_port *port)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	int fb_id, i;
+	struct igt_fb fb;
+	bool found, ok;
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_avi infoframe_avi;
+	uint8_t vic = 16; /* TODO: test more VICs */
+	const struct vic_mode *vic_mode;
+	uint32_t aspect_ratio;
+	enum infoframe_avi_picture_aspect_ratio frame_ar;
+
+	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port,
+					  IGT_CUSTOM_EDID_ASPECT_RATIO);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	vic_mode = &vic_modes[vic];
+	aspect_ratio = vic_mode->picture_ar;
+
+	found = false;
+	igt_assert(connector->count_modes > 0);
+	for (i = 0; i < connector->count_modes; i++) {
+		mode = &connector->modes[i];
+
+		if (vic_mode_matches_drm(vic_mode, mode)) {
+			found = true;
+			break;
+		}
+	}
+	igt_assert_f(found,
+		     "Failed to find mode with the correct aspect ratio\n");
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
+						 CHAMELIUM_INFOFRAME_AVI);
+	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
+
+	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
+				 infoframe->payload, infoframe->payload_size);
+	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
+
+	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
+
+	igt_debug("Checking AVI InfoFrame\n");
+	igt_debug("Picture aspect ratio: got %d, expected %d\n",
+		  infoframe_avi.picture_aspect_ratio, frame_ar);
+	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
+		  infoframe_avi.vic, vic);
+
+	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
+	igt_assert(infoframe_avi.vic == vic);
+
+	chamelium_infoframe_destroy(infoframe);
+	igt_remove_fb(data->drm_fd, &fb);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_planes_random_desc[] =
+	"Setup a few overlay planes with random parameters, capture the frame "
+	"and check it matches the expected output";
+static void test_display_planes_random(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum chamelium_check check)
+{
+	igt_output_t *output;
+	drmModeModeInfo *mode;
+	igt_plane_t *primary_plane;
+	struct igt_fb primary_fb;
+	struct igt_fb result_fb;
+	struct igt_fb *overlay_fbs;
+	igt_crc_t *crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
+	unsigned int overlay_planes_max = 0;
+	unsigned int overlay_planes_count;
+	cairo_surface_t *result_surface;
+	int captured_frame_count;
+	bool allow_scaling;
+	bool allow_yuv;
+	unsigned int i;
+	unsigned int fb_id;
+
+	switch (check) {
+	case CHAMELIUM_CHECK_CRC:
+		allow_scaling = false;
+		allow_yuv = false;
+		break;
+	case CHAMELIUM_CHECK_CHECKERBOARD:
+		allow_scaling = true;
+		allow_yuv = true;
+		break;
+	default:
+		igt_assert(false);
+	}
+
+	srand(time(NULL));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Find the connector and pipe. */
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+
+	mode = igt_output_get_mode(output);
+
+	/* Get a framebuffer for the primary plane. */
+	primary_plane =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary_plane);
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
+	igt_assert(fb_id > 0);
+
+	/* Get a framebuffer for the cairo composition result. */
+	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
+			      &result_fb);
+	igt_assert(fb_id > 0);
+
+	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
+
+	/* Paint the primary framebuffer on the result surface. */
+	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
+			 &primary_fb);
+
+	/* Configure the primary plane. */
+	igt_plane_set_fb(primary_plane, &primary_fb);
+
+	overlay_planes_max =
+		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
+
+	/* Limit the number of planes to a reasonable scene. */
+	overlay_planes_max = min(overlay_planes_max, 4u);
+
+	overlay_planes_count = (rand() % overlay_planes_max) + 1;
+	igt_debug("Using %d overlay planes\n", overlay_planes_count);
+
+	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
+
+	for (i = 0; i < overlay_planes_count; i++) {
+		struct igt_fb *overlay_fb = &overlay_fbs[i];
+		igt_plane_t *plane = igt_output_get_plane_type_index(
+			output, DRM_PLANE_TYPE_OVERLAY, i);
+		igt_assert(plane);
+
+		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
+					 result_surface, allow_scaling,
+					 allow_yuv);
+	}
+
+	cairo_surface_destroy(result_surface);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&result_fb);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == 1);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &result_fb, 0);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &result_fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	for (i = 0; i < overlay_planes_count; i++)
+		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
+
+	free(overlay_fbs);
+
+	igt_remove_fb(data->drm_fd, &primary_fb);
+	igt_remove_fb(data->drm_fd, &result_fb);
+}
+
+IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-single", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("dp-crc-fast", DisplayPort)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-multiple", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("dp-frame-dump", DisplayPort)
+			test_display_frame_dump(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-single", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("hdmi-crc-fast", HDMIA)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-multiple", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CRC, 1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-crc-planes-random", HDMIA)
+			test_display_planes_random(&data, port,
+						   CHAMELIUM_CHECK_CRC);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (!igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CHECKERBOARD,
+						1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-cmp-planes-random", HDMIA)
+			test_display_planes_random(
+				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("hdmi-frame-dump", HDMIA)
+			test_display_frame_dump(&data, port);
+
+		igt_describe(test_display_aspect_ratio_desc);
+		connector_subtest("hdmi-aspect-ratio", HDMIA)
+			test_display_aspect_ratio(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("vga-frame-dump", VGA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_ANALOG, 1);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
new file mode 100644
index 00000000..b9544288
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+
+void chamelium_init_test(chamelium_data_t *data)
+{
+	int i;
+
+	/* So fbcon doesn't try to reprobe things itself */
+	kmstest_set_vt_graphics_mode();
+
+	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
+	igt_display_require(&data->display, data->drm_fd);
+	igt_require(data->display.is_atomic);
+
+	/*
+	 * XXX: disabling modeset, can be removed when
+	 * igt_display_require will start doing this for us
+	 */
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	/* we need to initalize chamelium after igt_display_require */
+	data->chamelium = chamelium_init(data->drm_fd, &data->display);
+	igt_require(data->chamelium);
+
+	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
+
+	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
+		data->edids[i] = chamelium_new_edid(data->chamelium,
+						    igt_kms_get_custom_edid(i));
+	}
+}
+
+/* Wait for hotplug and return the remaining time left from timeout */
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
+{
+	struct timespec start, end;
+	int elapsed;
+	bool detected;
+
+	igt_assert_eq(igt_gettime(&start), 0);
+	detected = igt_hotplug_detected(mon, *timeout);
+	igt_assert_eq(igt_gettime(&end), 0);
+
+	elapsed = igt_time_elapsed(&start, &end);
+	igt_assert_lte(0, elapsed);
+	*timeout = max(0, *timeout - elapsed);
+
+	return detected;
+}
+
+/**
+ * chamelium_wait_for_connector_after_hotplug:
+ *
+ * Waits for the connector attached to @port to have a status of @status after
+ * it's plugged/unplugged.
+ *
+ */
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status)
+{
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int hotplug_count = 0;
+
+	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
+		  chamelium_port_get_name(port),
+		  kmstest_connector_status_str(status));
+
+	while (timeout > 0) {
+		if (!chamelium_wait_for_hotplug(mon, &timeout))
+			break;
+
+		hotplug_count++;
+
+		if (chamelium_reprobe_connector(&data->display, data->chamelium,
+						port) == status)
+			return;
+	}
+
+	igt_assert_f(
+		false,
+		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
+		chamelium_port_get_name(port),
+		kmstest_connector_status_str(status),
+		kmstest_connector_status_str(chamelium_reprobe_connector(
+			&data->display, data->chamelium, port)),
+		hotplug_count);
+}
+
+/**
+ * chamelium_port_get_connector:
+ * @data: The Chamelium data instance to use
+ * @port: The chamelium port to prepare its connector
+ * @edid: The chamelium's default EDID has a lot of resolutions, way more then
+ * 		  we need to test. Additionally the default EDID doesn't support
+ *        HDMI audio.
+ *
+ * Makes sure the output display of the connector attached to @port is connected
+ * and ready for use.
+ *
+ * Returns: a pointer to the enabled igt_output_t
+ */
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	/* The chamelium's default EDID has a lot of resolutions, way more then
+	 * we need to test. Additionally the default EDID doesn't support HDMI
+	 * audio.
+	 */
+	chamelium_set_edid(data, port, edid);
+
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_display_reset(display);
+
+	output = chamelium_get_output_for_port(data, port);
+
+	/* Refresh pipe to update connected status */
+	igt_output_set_pipe(output, PIPE_NONE);
+
+	pipe = chamelium_get_pipe_for_output(display, output);
+	igt_output_set_pipe(output, pipe);
+
+	return output;
+}
+
+/**
+ * chamelium_enable_output:
+ *
+ * Modesets the connector attached to @port for the assigned @mode and draws the
+ * @fb.
+ *
+ */
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb)
+{
+	igt_display_t *display = output->display;
+	igt_plane_t *primary =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+
+	igt_assert(primary);
+
+	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
+	igt_plane_set_fb(primary, fb);
+	igt_output_override_mode(output, mode);
+
+	/* Clear any color correction values that might be enabled */
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_GAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
+		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
+					       NULL, 0);
+
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
+		usleep(250000);
+
+	drmModeFreeConnector(connector);
+}
+
+/* Return pipe attached to @outpu.t */
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output)
+{
+	enum pipe pipe;
+
+	for_each_pipe(display, pipe) {
+		if (igt_pipe_connector_valid(pipe, output)) {
+			return pipe;
+		}
+	}
+
+	igt_assert_f(false, "No pipe found for output %s\n",
+		     igt_output_name(output));
+}
+
+static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
+					 size_t height, size_t stride,
+					 size_t block_size)
+{
+	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
+			      0xffffffff };
+	unsigned i, j;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			*(data + i * stride / 4 +
+			  j) = colors[((j / block_size) + (i / block_size)) % 5];
+}
+
+/**
+ * chamelium_get_pattern_fb:
+ *
+ * Creates an @fb with an xr24 pattern and returns the fb_id.
+ *
+ */
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb)
+{
+	int fb_id;
+	void *ptr;
+
+	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
+
+	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
+			      DRM_FORMAT_MOD_LINEAR, fb);
+	igt_assert(fb_id > 0);
+
+	ptr = igt_fb_map_buffer(fb->fd, fb);
+	igt_assert(ptr);
+
+	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
+				     block_size);
+	igt_fb_unmap_buffer(fb, ptr);
+
+	return fb_id;
+}
+
+/* Generate a simple @fb for the size of @mode. */
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode)
+{
+	int fb_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, fb);
+
+	igt_assert(fb_id > 0);
+}
+
+/* Returns the first preferred mode for the connector attached to @port. */
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(chamelium, port, false);
+	drmModeModeInfo mode;
+	igt_assert(&connector->modes[0] != NULL);
+	memcpy(&mode, &connector->modes[0], sizeof(mode));
+	drmModeFreeConnector(connector);
+	return mode;
+}
+
+/* Returns the igt display output for the connector attached to @port. */
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, true);
+	igt_output_t *output =
+		igt_output_from_connector(&data->display, connector);
+	drmModeFreeConnector(connector);
+	igt_assert(output != NULL);
+	return output;
+}
+
+/* Set the EDID of index @edid to Chamelium's @port. */
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid)
+{
+	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
+}
+
+/**
+ * chamelium_check_analog_bridge:
+ *
+ * Check if the connector associalted to @port is an analog bridge by checking
+ * if it has its own EDID.
+ *
+ */
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+	uint64_t edid_blob_id;
+	const struct edid *edid;
+	char edid_vendor[3];
+
+	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
+		drmModeFreeConnector(connector);
+		return false;
+	}
+
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	edid = (const struct edid *)edid_blob->data;
+	edid_get_mfg(edid, edid_vendor);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+
+	/* Analog bridges provide their own EDID */
+	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
+	    edid_vendor[2] != 'T')
+		return true;
+
+	return false;
+}
\ No newline at end of file
diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
new file mode 100644
index 00000000..09fa4829
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+
+#include "igt.h"
+
+#define ONLINE_TIMEOUT 20 /* seconds */
+
+#define for_each_port(p, port)                                 \
+	for (p = 0, port = data.ports[p]; p < data.port_count; \
+	     p++, port = data.ports[p])
+
+#define connector_subtest(name__, type__)                           \
+	igt_subtest(name__)                                         \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+/*
+ * The chamelium data structure is used to store all the information known about
+ * chamelium to run the tests.
+ */
+typedef struct {
+	struct chamelium *chamelium;
+	struct chamelium_port **ports;
+	igt_display_t display;
+	int port_count;
+
+	int drm_fd;
+
+	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
+} chamelium_data_t;
+
+void chamelium_init_test(chamelium_data_t *data);
+
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status);
+
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid);
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb);
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output);
+
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb);
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode);
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port);
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port);
+
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid);
+
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port);
+
+#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
new file mode 100644
index 00000000..8a4e1aba
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_hpd.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the HPD functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "kms_chamelium_helper.h"
+
+#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
+#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
+
+#define HPD_TOGGLE_COUNT_VGA 5
+#define HPD_TOGGLE_COUNT_DP_HDMI 15
+#define HPD_TOGGLE_COUNT_FAST 3
+
+enum test_modeset_mode {
+	TEST_MODESET_ON,
+	TEST_MODESET_ON_OFF,
+	TEST_MODESET_OFF,
+};
+
+static void try_suspend_resume_hpd(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   enum igt_suspend_state state,
+				   enum igt_suspend_test test,
+				   struct udev_monitor *mon, bool connected)
+{
+	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
+						     DRM_MODE_CONNECTED;
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int delay;
+	int p;
+
+	igt_flush_uevents(mon);
+
+	delay = igt_get_autoresume_delay(state) * 1000 / 2;
+
+	if (port) {
+		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
+					      !connected);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			port = data->ports[p];
+			chamelium_schedule_hpd_toggle(data->chamelium, port,
+						      delay, !connected);
+		}
+
+		port = NULL;
+	}
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	if (port) {
+		igt_assert_eq(chamelium_reprobe_connector(
+				      &data->display, data->chamelium, port),
+			      target_state);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			drmModeConnection current_state;
+
+			port = data->ports[p];
+			/*
+			 * There could be as many hotplug events sent by
+			 * driver as connectors we scheduled an HPD toggle on
+			 * above, depending on timing. So if we're not seeing
+			 * the expected connector state try to wait for an HPD
+			 * event for each connector/port.
+			 */
+			current_state = chamelium_reprobe_connector(
+				&data->display, data->chamelium, port);
+			if (p > 0 && current_state != target_state) {
+				igt_assert(chamelium_wait_for_hotplug(
+					mon, &timeout));
+				current_state = chamelium_reprobe_connector(
+					&data->display, data->chamelium, port);
+			}
+
+			igt_assert_eq(current_state, target_state);
+		}
+
+		port = NULL;
+	}
+}
+
+static const char test_basic_hotplug_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug";
+static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
+			 int toggle_count, enum test_modeset_mode modeset_mode)
+{
+	int i;
+	enum pipe pipe;
+	struct igt_fb fb = { 0 };
+	drmModeModeInfo mode;
+	struct udev_monitor *mon = igt_watch_uevents();
+	igt_output_t *output = chamelium_get_output_for_port(data, port);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+
+	for (i = 0; i < toggle_count; i++) {
+		igt_flush_uevents(mon);
+
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF ||
+		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
+			if (i == 0) {
+				/* We can only get mode and pipe once we are
+				 * connected */
+				output = chamelium_get_output_for_port(data,
+								       port);
+				pipe = chamelium_get_pipe_for_output(
+					&data->display, output);
+				mode = chamelium_get_mode_for_port(
+					data->chamelium, port);
+				chamelium_create_fb_for_mode(data, &fb, &mode);
+			}
+
+			igt_output_set_pipe(output, pipe);
+			chamelium_enable_output(data, port, output, &mode, &fb);
+		}
+
+		/* Now check if we get a hotplug from disconnection */
+		chamelium_unplug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF) {
+			igt_output_set_pipe(output, PIPE_NONE);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static const char test_hotplug_for_each_pipe_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug for each pipe with valid output";
+static void test_hotplug_for_each_pipe(chamelium_data_t *data,
+				       struct chamelium_port *port)
+{
+	igt_output_t *output;
+	enum pipe pipe;
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	/* Disconnect if any port got connected */
+	chamelium_unplug(data->chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_DISCONNECTED);
+
+	for_each_pipe(&data->display, pipe) {
+		igt_flush_uevents(mon);
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+		output = chamelium_get_output_for_port(data, port);
+
+		/* If pipe is valid for output then set it */
+		if (igt_pipe_connector_valid(pipe, output)) {
+			igt_output_set_pipe(output, pipe);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+
+		chamelium_unplug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+		igt_flush_uevents(mon);
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_suspend_resume_hpd_desc[] =
+	"Toggle HPD during suspend, check that uevents are sent and connector "
+	"status is updated";
+static void test_suspend_resume_hpd(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_suspend_state state,
+				    enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_suspend_resume_hpd_common_desc[] =
+	"Toggle HPD during suspend on all connectors, check that uevents are "
+	"sent and connector status is updated";
+static void test_suspend_resume_hpd_common(chamelium_data_t *data,
+					   enum igt_suspend_state state,
+					   enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	struct chamelium_port *port;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		port = data->ports[p];
+		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_without_ddc_desc[] =
+	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
+static void test_hpd_without_ddc(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+	igt_flush_uevents(mon);
+
+	/* Disable the DDC on the connector and make sure we still get a
+	 * hotplug
+	 */
+	chamelium_port_set_ddc_state(data->chamelium, port, false);
+	chamelium_plug(data->chamelium, port);
+
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_assert_eq(chamelium_reprobe_connector(&data->display,
+						  data->chamelium, port),
+		      DRM_MODE_CONNECTED);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_storm_detect_desc[] =
+	"Trigger a series of hotplugs in a very small timeframe to simulate a"
+	"bad cable, check the kernel falls back to polling to avoid a hotplug "
+	"storm";
+static void test_hpd_storm_detect(chamelium_data_t *data,
+				  struct chamelium_port *port, int width)
+{
+	struct udev_monitor *mon;
+	int count = 0;
+
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 1);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(igt_hpd_storm_detected(data->drm_fd));
+
+	mon = igt_watch_uevents();
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+
+	/*
+	 * Polling should have been enabled by the HPD storm at this point,
+	 * so we should only get at most 1 hotplug event
+	 */
+	igt_until_timeout(5)
+		count += igt_hotplug_detected(mon, 1);
+	igt_assert_lt(count, 2);
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_hpd_storm_disable_desc[] =
+	"Disable HPD storm detection, trigger a storm and check the kernel "
+	"doesn't detect one";
+static void test_hpd_storm_disable(chamelium_data_t *data,
+				   struct chamelium_port *port, int width)
+{
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
+
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-suspend", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("dp-hpd-storm", DisplayPort)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_DP);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("dp-hpd-storm-disable", DisplayPort)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_DP);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("hdmi-hpd-storm", HDMIA)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_HDMI);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_HDMI);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-enable-disable-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-with-enabled-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-suspend", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-hibernate", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_without_ddc_desc);
+		connector_subtest("vga-hpd-without-ddc", VGA)
+			test_hpd_without_ddc(&data, port);
+	}
+
+	igt_describe("Tests that operate on all connectors");
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(data.port_count);
+		}
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-suspend")
+			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
+						       SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-hibernate")
+			test_suspend_resume_hpd_common(&data,
+						       SUSPEND_STATE_DISK,
+						       SUSPEND_TEST_DEVICES);
+	}
+
+	igt_describe(test_hotplug_for_each_pipe_desc);
+	connector_subtest("vga-hpd-for-each-pipe", VGA)
+		test_hotplug_for_each_pipe(&data, port);
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 0d307730..6e5cc436 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
 # is too costly in comparison to the value
 # provided.
 ###############################################
-igt@kms_chamelium@hdmi-.*-planes-random
+igt@kms_chamelium_frames@hdmi-.*-planes-random
 ###############################################
 # Broadcom
 ###############################################
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index f57f8ff3..fb4c0f73 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
 igt@kms_addfb_basic@unused-offsets
 igt@kms_addfb_basic@unused-pitches
 igt@kms_busy@basic
-igt@kms_chamelium@dp-hpd-fast
-igt@kms_chamelium@dp-edid-read
-igt@kms_chamelium@dp-crc-fast
-igt@kms_chamelium@hdmi-hpd-fast
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@vga-hpd-fast
-igt@kms_chamelium@vga-edid-read
+igt@kms_chamelium_hpd@dp-hpd-fast
+igt@kms_chamelium_edid@dp-edid-read
+igt@kms_chamelium_frames@dp-crc-fast
+igt@kms_chamelium_hpd@hdmi-hpd-fast
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_hpd@vga-hpd-fast
+igt@kms_chamelium_edid@vga-edid-read
 igt@kms_prop_blob@basic
 igt@kms_cursor_legacy@basic-busy-flip-before-cursor
 igt@kms_cursor_legacy@basic-flip-after-cursor
@@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
 igt@i915_suspend@basic-s3-without-i915
 igt@gem_exec_suspend@basic-s0
 igt@gem_exec_suspend@basic-s3
-igt@kms_chamelium@common-hpd-after-suspend
+igt@kms_chamelium_hpd@common-hpd-after-suspend
 igt@kms_pipe_crc_basic@suspend-read-crc
diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
index f0ae30e3..f9242232 100644
--- a/tests/kms_color_helper.h
+++ b/tests/kms_color_helper.h
@@ -27,7 +27,7 @@
 
 /*
  * This header is for code that is shared between kms_color.c and
- * kms_color_chamelium.c. Reusability elsewhere can be questionable.
+ * kms_chamelium_color.c. Reusability elsewhere can be questionable.
  */
 
 #include <math.h>
diff --git a/tests/meson.build b/tests/meson.build
index 5c052e73..b52399d5 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -260,7 +260,10 @@ msm_progs = [
 ]
 
 chamelium_progs = [
-	'kms_chamelium',
+	'kms_chamelium_audio',
+	'kms_chamelium_edid',
+	'kms_chamelium_frames',
+	'kms_chamelium_hpd',
 ]
 
 test_deps = [ igt_deps ]
@@ -309,7 +312,8 @@ endforeach
 if chamelium.found()
 	foreach prog : chamelium_progs
 		test_executables += executable(prog,
-				 join_paths('chamelium', prog + '.c'),
+				 [join_paths('chamelium', prog + '.c'), 
+				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
 				 dependencies : test_deps,
 				 install_dir : libexecdir,
 				 install_rpath : libexecdir_rpathdir,
@@ -436,13 +440,13 @@ test_executables += executable('kms_color',
 test_list += 'kms_color'
 
 if chamelium.found()
-       test_executables += executable('kms_color_chamelium',
-                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
+       test_executables += executable('kms_chamelium_color',
+                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
                              dependencies : test_deps + [ chamelium ],
                              install_dir : libexecdir,
                              install_rpath : libexecdir_rpathdir,
                              install : true)
-       test_list += 'kms_color_chamelium'
+       test_list += 'kms_chamelium_color'
 endif
 
 test_executables += executable('sw_sync', 'sw_sync.c',
diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
index dd45d12a..a5521021 100644
--- a/tests/vc4_ci/vc4-chamelium-fast.testlist
+++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
@@ -1,14 +1,14 @@
-igt@kms_chamelium@hdmi-crc-abgr8888
-igt@kms_chamelium@hdmi-crc-argb1555
-igt@kms_chamelium@hdmi-crc-argb8888
-igt@kms_chamelium@hdmi-crc-bgr565
-igt@kms_chamelium@hdmi-crc-bgr888
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@hdmi-crc-rgb565
-igt@kms_chamelium@hdmi-crc-rgb888
-igt@kms_chamelium@hdmi-crc-xbgr8888
-igt@kms_chamelium@hdmi-crc-xrgb1555
-igt@kms_chamelium@hdmi-crc-xrgb8888
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-hpd
-igt@kms_chamelium@hdmi-hpd-fast
+igt@kms_chamelium_frames@hdmi-crc-abgr8888
+igt@kms_chamelium_frames@hdmi-crc-argb1555
+igt@kms_chamelium_frames@hdmi-crc-argb8888
+igt@kms_chamelium_frames@hdmi-crc-bgr565
+igt@kms_chamelium_frames@hdmi-crc-bgr888
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_frames@hdmi-crc-rgb565
+igt@kms_chamelium_frames@hdmi-crc-rgb888
+igt@kms_chamelium_frames@hdmi-crc-xbgr8888
+igt@kms_chamelium_frames@hdmi-crc-xrgb1555
+igt@kms_chamelium_frames@hdmi-crc-xrgb8888
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_hpd@hdmi-hpd
+igt@kms_chamelium_hpd@hdmi-hpd-fast
-- 
2.39.0.rc0.267.gcb52ba06e7-goog

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (7 preceding siblings ...)
  2022-12-02  8:02 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
@ 2022-12-06 19:19 ` Patchwork
  2022-12-06 19:51 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-06 19:19 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3)
URL   : https://patchwork.freedesktop.org/series/111501/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/756315 for the overview.

build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057333):
  /usr/include/xf86drmMode.h:545:39: error: unknown type name ‘uint32_t’
   extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
                                         ^~~~~~~~
  ../tests/chamelium/kms_chamelium_edid.c: In function ‘igt_custom_edid_type_read’:
  ../tests/chamelium/kms_chamelium_edid.c:144:14: error: implicit declaration of function ‘drmModeGetPropertyBlob’; did you mean ‘drmModeFreePropertyBlob’? [-Werror=implicit-function-declaration]
    edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
                ^~~~~~~~~~~~~~~~~~~~~~
                drmModeFreePropertyBlob
  ../tests/chamelium/kms_chamelium_edid.c:144:14: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
  ../tests/chamelium/kms_chamelium_edid.c:144:12: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
              ^
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1670353936:step_script
  section_start:1670353936:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670353936:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057328):
  /usr/include/xf86drmMode.h:545:39: error: unknown type name ‘uint32_t’
    545 | extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
        |                                       ^~~~~~~~
  ../tests/chamelium/kms_chamelium_edid.c: In function ‘igt_custom_edid_type_read’:
  ../tests/chamelium/kms_chamelium_edid.c:144:14: error: implicit declaration of function ‘drmModeGetPropertyBlob’; did you mean ‘drmModeFreePropertyBlob’? [-Werror=implicit-function-declaration]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |              ^~~~~~~~~~~~~~~~~~~~~~
        |              drmModeFreePropertyBlob
  ../tests/chamelium/kms_chamelium_edid.c:144:14: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
  ../tests/chamelium/kms_chamelium_edid.c:144:12: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |            ^
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1670353945:step_script
  section_start:1670353945:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670353947:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057332):
          uint32_t bpp;
          ^
  /usr/include/xf86drmMode.h:221:2: error: unknown type name 'uint32_t'
          uint32_t depth;
          ^
  /usr/include/xf86drmMode.h:223:2: error: unknown type name 'uint32_t'
          uint32_t handle;
          ^
  /usr/include/xf86drmMode.h:229:2: error: unknown type name 'uint32_t'
          uint32_t id;
          ^
  fatal error: too many errors emitted, stopping now [-ferror-limit=]
  20 errors generated.
  ninja: build stopped: subcommand failed.
  section_end:1670354021:step_script
  section_start:1670354021:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670354022:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057331):
  /usr/include/xf86drmMode.h:545:39: error: unknown type name ‘uint32_t’
    545 | extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
        |                                       ^~~~~~~~
  ../tests/chamelium/kms_chamelium_edid.c: In function ‘igt_custom_edid_type_read’:
  ../tests/chamelium/kms_chamelium_edid.c:144:14: error: implicit declaration of function ‘drmModeGetPropertyBlob’; did you mean ‘drmModeFreePropertyBlob’? [-Werror=implicit-function-declaration]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |              ^~~~~~~~~~~~~~~~~~~~~~
        |              drmModeFreePropertyBlob
  ../tests/chamelium/kms_chamelium_edid.c:144:14: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
  ../tests/chamelium/kms_chamelium_edid.c:144:12: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |            ^
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1670353944:step_script
  section_start:1670353944:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670353945:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057329):
  /usr/include/xf86drmMode.h:545:39: error: unknown type name ‘uint32_t’
    545 | extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
        |                                       ^~~~~~~~
  ../tests/chamelium/kms_chamelium_edid.c: In function ‘igt_custom_edid_type_read’:
  ../tests/chamelium/kms_chamelium_edid.c:144:14: error: implicit declaration of function ‘drmModeGetPropertyBlob’; did you mean ‘drmModeFreePropertyBlob’? [-Werror=implicit-function-declaration]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |              ^~~~~~~~~~~~~~~~~~~~~~
        |              drmModeFreePropertyBlob
  ../tests/chamelium/kms_chamelium_edid.c:144:14: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
  ../tests/chamelium/kms_chamelium_edid.c:144:12: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |            ^
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1670353953:step_script
  section_start:1670353953:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670353953:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33057330):
  /usr/include/xf86drmMode.h:545:39: error: unknown type name ‘uint32_t’
    545 | extern int drmModeRevokeLease(int fd, uint32_t lessee_id);
        |                                       ^~~~~~~~
  ../tests/chamelium/kms_chamelium_edid.c: In function ‘igt_custom_edid_type_read’:
  ../tests/chamelium/kms_chamelium_edid.c:144:14: error: implicit declaration of function ‘drmModeGetPropertyBlob’; did you mean ‘drmModeFreePropertyBlob’? [-Werror=implicit-function-declaration]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |              ^~~~~~~~~~~~~~~~~~~~~~
        |              drmModeFreePropertyBlob
  ../tests/chamelium/kms_chamelium_edid.c:144:14: warning: nested extern declaration of ‘drmModeGetPropertyBlob’ [-Wnested-externs]
  ../tests/chamelium/kms_chamelium_edid.c:144:12: warning: assignment to ‘drmModePropertyBlobPtr’ {aka ‘struct _drmModePropertyBlob *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    144 |  edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
        |            ^
  cc1: some warnings being treated as errors
  ninja: build stopped: subcommand failed.
  section_end:1670353953:step_script
  section_start:1670353953:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670353954:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/756315

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (8 preceding siblings ...)
  2022-12-06 19:19 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3) Patchwork
@ 2022-12-06 19:51 ` Patchwork
  2022-12-06 23:45 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4) Patchwork
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-06 19:51 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 23942 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3)
URL   : https://patchwork.freedesktop.org/series/111501/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8207
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_8207 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_8207, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/index.html

Participating hosts (30 -> 42)
------------------------------

  Additional (13): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-adlp-9 fi-bsw-n3050 bat-dg1-5 bat-dg2-8 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
  Missing    (1): fi-cfl-8700k 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8207:

### IGT changes ###

#### Possible regressions ####

  * igt@i915_selftest@live@late_gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@i915_selftest@live@late_gt_pm.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +7 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +8 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - {bat-rplp-1}:       NOTRUN -> [SKIP][7] +8 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - {bat-adln-1}:       NOTRUN -> [SKIP][8] +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - {bat-adlp-9}:       NOTRUN -> [SKIP][9] +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-rkl-11600:       NOTRUN -> [SKIP][10] +8 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-adls-5}:       NOTRUN -> [SKIP][11] +7 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - bat-dg1-5:          NOTRUN -> [SKIP][12] +8 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg1-7}:        NOTRUN -> [SKIP][13] +8 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg2-9}:        NOTRUN -> [SKIP][14] +8 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - {bat-adlp-6}:       NOTRUN -> [SKIP][15] +7 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-icl-u2:          NOTRUN -> [SKIP][16] +8 similar issues
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-jsl-3}:        NOTRUN -> [SKIP][17] +8 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-rkl-guc:         NOTRUN -> [SKIP][18] +7 similar issues
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-11}:       NOTRUN -> [SKIP][19] +8 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - bat-adlp-4:         NOTRUN -> [SKIP][20] +8 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-8}:        NOTRUN -> [SKIP][21] +8 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-adlm-1}:       NOTRUN -> [SKIP][22] +8 similar issues
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html

  
#### Suppressed ####

  The following results come from untrusted machines, tests, or statuses.
  They do not affect the overall result.

  * igt@gem_exec_fence@basic-busy@bcs0:
    - {bat-rpls-2}:       [PASS][23] -> [DMESG-WARN][24]
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rpls-2/igt@gem_exec_fence@basic-busy@bcs0.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-rpls-2/igt@gem_exec_fence@basic-busy@bcs0.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12475 and IGTPW_8207:

### New IGT tests (9) ###

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 41 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 1 pass(s) 40 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 41 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 41 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 1 pass(s) 40 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 41 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 1 pass(s) 40 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 41 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8207 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@debugfs_test@basic-hwmon:
    - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@debugfs_test@basic-hwmon.html

  * igt@gem_exec_gttfill@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][27] ([fdo#109271] / [i915#2190])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][28] ([fdo#109271] / [i915#4613]) +3 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-bsw-nick:        NOTRUN -> [SKIP][29] ([fdo#109271]) +48 similar issues
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
    - bat-adlp-4:         NOTRUN -> [SKIP][30] ([i915#4613]) +3 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@gem_mmap@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][31] ([i915#4083])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@gem_mmap@basic.html

  * igt@gem_tiled_blits@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][32] ([i915#4077]) +2 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@gem_tiled_blits@basic.html

  * igt@gem_tiled_pread_basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4079]) +1 similar issue
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@gem_tiled_pread_basic.html
    - bat-adlp-4:         NOTRUN -> [SKIP][34] ([i915#3282])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@gem_tiled_pread_basic.html

  * igt@i915_module_load@load:
    - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][35] ([i915#7430])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-bsw-n3050/igt@i915_module_load@load.html

  * igt@i915_pm_backlight@basic-brightness:
    - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#7561])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html

  * igt@i915_pm_rps@basic-api:
    - bat-adlp-4:         NOTRUN -> [SKIP][37] ([i915#6621])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@i915_pm_rps@basic-api.html
    - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#6621])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@i915_pm_rps@basic-api.html

  * igt@i915_selftest@live@gt_heartbeat:
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][39] ([i915#5334])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@i915_selftest@live@gt_heartbeat.html

  * igt@i915_selftest@live@gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][40] ([i915#1886])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html

  * igt@i915_selftest@live@hangcheck:
    - fi-rkl-guc:         [PASS][41] -> [INCOMPLETE][42] ([i915#4983])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@hangcheck.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-rkl-guc/igt@i915_selftest@live@hangcheck.html

  * igt@kms_addfb_basic@basic-x-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][43] ([i915#4212]) +7 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html

  * igt@kms_addfb_basic@basic-y-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][44] ([i915#4215])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - fi-pnv-d510:        NOTRUN -> [SKIP][45] ([fdo#109271]) +8 similar issues
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-cfl-guc:         NOTRUN -> [SKIP][46] ([fdo#109271]) +8 similar issues
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - fi-ilk-650:         NOTRUN -> [SKIP][47] ([fdo#109271]) +8 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - fi-cfl-8109u:       NOTRUN -> [SKIP][48] ([fdo#109271]) +8 similar issues
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][49] ([fdo#109271]) +8 similar issues
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][50] ([fdo#109271]) +7 similar issues
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - fi-glk-j4005:       NOTRUN -> [SKIP][51] ([fdo#109271]) +8 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-snb-2600:        NOTRUN -> [SKIP][52] ([fdo#109271]) +8 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-skl-6700k2:      NOTRUN -> [SKIP][53] ([fdo#109271]) +4 similar issues
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - fi-blb-e6850:       NOTRUN -> [SKIP][54] ([fdo#109271]) +8 similar issues
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
    - {bat-kbl-2}:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-apl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][57] ([fdo#109271]) +7 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-skl-guc:         NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-hsw-4770:        NOTRUN -> [SKIP][60] ([fdo#109271]) +8 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
    - bat-adlp-4:         NOTRUN -> [SKIP][63] ([i915#4103])
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
    - bat-dg1-5:          NOTRUN -> [SKIP][64] ([i915#4103] / [i915#4213])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html

  * igt@kms_force_connector_basic@force-load-detect:
    - bat-adlp-4:         NOTRUN -> [SKIP][65] ([i915#4093]) +3 similar issues
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
    - bat-dg1-5:          NOTRUN -> [SKIP][66] ([fdo#109285])
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pipe_crc_basic@suspend-read-crc:
    - bat-adlp-4:         NOTRUN -> [SKIP][67] ([i915#3546])
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html

  * igt@kms_psr@primary_page_flip:
    - bat-dg1-5:          NOTRUN -> [SKIP][68] ([i915#1072] / [i915#4078]) +3 similar issues
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_psr@primary_page_flip.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - bat-dg1-5:          NOTRUN -> [SKIP][69] ([i915#3555])
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
    - bat-adlp-4:         NOTRUN -> [SKIP][70] ([i915#3555] / [i915#4579])
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@prime_vgem@basic-fence-read:
    - bat-dg1-5:          NOTRUN -> [SKIP][71] ([i915#3708]) +3 similar issues
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@prime_vgem@basic-fence-read.html

  * igt@prime_vgem@basic-gtt:
    - bat-dg1-5:          NOTRUN -> [SKIP][72] ([i915#3708] / [i915#4077]) +1 similar issue
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@prime_vgem@basic-gtt.html

  * igt@prime_vgem@basic-userptr:
    - bat-adlp-4:         NOTRUN -> [SKIP][73] ([fdo#109295] / [i915#3301] / [i915#3708])
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@prime_vgem@basic-userptr.html
    - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#3708] / [i915#4873])
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-dg1-5/igt@prime_vgem@basic-userptr.html

  * igt@prime_vgem@basic-write:
    - bat-adlp-4:         NOTRUN -> [SKIP][75] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adlp-4/igt@prime_vgem@basic-write.html

  * igt@runner@aborted:
    - fi-bsw-n3050:       NOTRUN -> [FAIL][76] ([i915#4312])
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-bsw-n3050/igt@runner@aborted.html

  
#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - {bat-rplp-1}:       [DMESG-WARN][77] ([i915#2867]) -> [PASS][78]
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html

  * igt@i915_selftest@live@requests:
    - {bat-rpls-2}:       [INCOMPLETE][79] ([i915#6257]) -> [PASS][80]
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rpls-2/igt@i915_selftest@live@requests.html
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-rpls-2/igt@i915_selftest@live@requests.html

  * igt@i915_selftest@live@slpc:
    - {bat-adln-1}:       [DMESG-FAIL][81] ([i915#6997]) -> [PASS][82]
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-adln-1/igt@i915_selftest@live@slpc.html
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/bat-adln-1/igt@i915_selftest@live@slpc.html

  * igt@i915_suspend@basic-s3-without-i915:
    - fi-rkl-11600:       [INCOMPLETE][83] ([i915#4817]) -> [PASS][84]
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-11600/igt@i915_suspend@basic-s3-without-i915.html
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/fi-rkl-11600/igt@i915_suspend@basic-s3-without-i915.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
  [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3637]: https://gitlab.freedesktop.org/drm/intel/issues/3637
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4817]: https://gitlab.freedesktop.org/drm/intel/issues/4817
  [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
  [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
  [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
  [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
  [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
  [i915#6106]: https://gitlab.freedesktop.org/drm/intel/issues/6106
  [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
  [i915#6367]: https://gitlab.freedesktop.org/drm/intel/issues/6367
  [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
  [i915#6559]: https://gitlab.freedesktop.org/drm/intel/issues/6559
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
  [i915#6997]: https://gitlab.freedesktop.org/drm/intel/issues/6997
  [i915#7077]: https://gitlab.freedesktop.org/drm/intel/issues/7077
  [i915#7346]: https://gitlab.freedesktop.org/drm/intel/issues/7346
  [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
  [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7084 -> IGTPW_8207

  CI-20190529: 20190529
  CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8207: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/index.html
  IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git


Testlist changes
----------------

+++ 71 lines
--- 73 lines

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8207/index.html

[-- Attachment #2: Type: text/html, Size: 27456 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] [PATCH v4] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-12-06 18:56   ` [igt-dev] [PATCH v3] " Mark Yacoub
@ 2022-12-06 23:22     ` Mark Yacoub
  2022-12-07 11:39       ` Kamil Konieczny
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Yacoub @ 2022-12-06 23:22 UTC (permalink / raw)
  To: igt-dev

[Why]
kms_chamelium tests file has grown so much and became a bit big to
manage.
Splitting specific tests like we do for kms_ tests into separate files
puts logically related functionalities into the same place so tests are
more clear.

[How]
Split kms_chamelium into 4 different tests, each testing something
specific. The tests are:
1. kms_chamelium_audio
2. kms_chamelium_edid
3. kms_chamelium_frames
4. kms_chamelium_hpd
5. kms_chamelium_color which used to be kms_color_chamelium but renamed
   for consistency.

All common code lives in kms_chamelium_helper and the function names
have a chamelium_ prefix.

Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
---
 docs/chamelium.txt                            |    2 +-
 lib/igt_edid.h                                |    1 +
 lib/igt_eld.h                                 |    1 +
 lib/monitor_edids/monitor_edids_helper.c      |    2 +-
 tests/chamelium/kms_chamelium.c               | 3132 -----------------
 tests/chamelium/kms_chamelium_audio.c         |  858 +++++
 ...olor_chamelium.c => kms_chamelium_color.c} |    0
 tests/chamelium/kms_chamelium_edid.c          |  535 +++
 tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
 tests/chamelium/kms_chamelium_helper.c        |  330 ++
 tests/chamelium/kms_chamelium_helper.h        |   74 +
 tests/chamelium/kms_chamelium_hpd.c           |  512 +++
 tests/intel-ci/blacklist.txt                  |    2 +-
 tests/intel-ci/fast-feedback.testlist         |   18 +-
 tests/kms_color_helper.h                      |    2 +-
 tests/meson.build                             |   14 +-
 tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
 17 files changed, 3432 insertions(+), 3164 deletions(-)
 delete mode 100644 tests/chamelium/kms_chamelium.c
 create mode 100644 tests/chamelium/kms_chamelium_audio.c
 rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
 create mode 100644 tests/chamelium/kms_chamelium_edid.c
 create mode 100644 tests/chamelium/kms_chamelium_frames.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.c
 create mode 100644 tests/chamelium/kms_chamelium_helper.h
 create mode 100644 tests/chamelium/kms_chamelium_hpd.c

diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index c4c22468..f82c8b0c 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -241,7 +241,7 @@ Current Support in IGT
 
 Support for the Chamelium platform in IGT is found in the following places:
 * lib/igt_chamelium.c: library with Chamelium-related helpers
-* tests/kms_chamelium.c: sub-tests using the Chamelium
+* tests/kms_chamelium_*.c: sub-tests using the Chamelium
 
 As of early April 2019, the following features are tested by IGT:
 * Pixel-by-pixel frame integrity tests for DP and HDMI
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 477f16c2..85a9ef5e 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdint.h>
+#include <stddef.h>
 
 #include <xf86drmMode.h>
 
diff --git a/lib/igt_eld.h b/lib/igt_eld.h
index 30d7012d..1a46b6d2 100644
--- a/lib/igt_eld.h
+++ b/lib/igt_eld.h
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stddef.h>
 
 #include "igt_edid.h"
 
diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
index 41f199bd..1cbf1c22 100644
--- a/lib/monitor_edids/monitor_edids_helper.c
+++ b/lib/monitor_edids/monitor_edids_helper.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 /*
  * A helper library for parsing and making use of real EDID data from monitors
  * and make them compatible with IGT and Chamelium.
diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
deleted file mode 100644
index 3c4b4d75..00000000
--- a/tests/chamelium/kms_chamelium.c
+++ /dev/null
@@ -1,3132 +0,0 @@
-/*
- * Copyright © 2016 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Lyude Paul <lyude@redhat.com>
- */
-
-#include "config.h"
-#include "igt.h"
-#include "igt_vc4.h"
-#include "igt_edid.h"
-#include "igt_eld.h"
-#include "igt_infoframe.h"
-#include "monitor_edids/dp_edids.h"
-#include "monitor_edids/hdmi_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,
-	TEST_MODESET_ON_OFF,
-	TEST_MODESET_OFF,
-};
-
-typedef struct {
-	struct chamelium *chamelium;
-	struct chamelium_port **ports;
-	igt_display_t display;
-	int port_count;
-
-	int drm_fd;
-
-	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
-} data_t;
-
-#define ONLINE_TIMEOUT 20 /* seconds */
-
-#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
-#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
-
-#define HPD_TOGGLE_COUNT_VGA 5
-#define HPD_TOGGLE_COUNT_DP_HDMI 15
-#define HPD_TOGGLE_COUNT_FAST 3
-
-static void
-get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
-{
-	drmModeConnector *connector;
-	uint64_t link_status;
-	drmModePropertyPtr prop;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		connector = chamelium_port_get_connector(data->chamelium,
-							 data->ports[p], false);
-
-		igt_assert(kmstest_get_property(data->drm_fd,
-						connector->connector_id,
-						DRM_MODE_OBJECT_CONNECTOR,
-						"link-status", NULL,
-						&link_status, &prop));
-
-		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
-
-		drmModeFreeProperty(prop);
-		drmModeFreeConnector(connector);
-	}
-}
-
-/* Wait for hotplug and return the remaining time left from timeout */
-static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
-{
-	struct timespec start, end;
-	int elapsed;
-	bool detected;
-
-	igt_assert_eq(igt_gettime(&start), 0);
-	detected = igt_hotplug_detected(mon, *timeout);
-	igt_assert_eq(igt_gettime(&end), 0);
-
-	elapsed = igt_time_elapsed(&start, &end);
-	igt_assert_lte(0, elapsed);
-	*timeout = max(0, *timeout - elapsed);
-
-	return detected;
-}
-
-static void
-wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
-				 struct chamelium_port *port,
-				 drmModeConnection status)
-{
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int hotplug_count = 0;
-
-	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
-			  chamelium_port_get_name(port),
-			  kmstest_connector_status_str(status));
-
-	while (timeout > 0) {
-		if (!wait_for_hotplug(mon, &timeout))
-			break;
-
-		hotplug_count++;
-
-		if (chamelium_reprobe_connector(&data->display, data->chamelium,
-						port) == status)
-			return;
-	}
-
-	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
-			    chamelium_port_get_name(port),
-			    kmstest_connector_status_str(status),
-			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
-}
-
-
-static int chamelium_vga_modes[][2] = {
-	{ 1600, 1200 },
-	{ 1920, 1200 },
-	{ 1920, 1080 },
-	{ 1680, 1050 },
-	{ 1280, 1024 },
-	{ 1280, 960 },
-	{ 1440, 900 },
-	{ 1280, 800 },
-	{ 1024, 768 },
-	{ 1360, 768 },
-	{ 1280, 720 },
-	{ 800, 600 },
-	{ 640, 480 },
-	{ -1, -1 },
-};
-
-static bool
-prune_vga_mode(data_t *data, drmModeModeInfo *mode)
-{
-	int i = 0;
-
-	while (chamelium_vga_modes[i][0] != -1) {
-		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
-		    mode->vdisplay == chamelium_vga_modes[i][1])
-			return false;
-
-		i++;
-	}
-
-	return true;
-}
-
-static bool
-check_analog_bridge(data_t *data, struct chamelium_port *port)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-	uint64_t edid_blob_id;
-	const struct edid *edid;
-	char edid_vendor[3];
-
-	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
-		drmModeFreeConnector(connector);
-		return false;
-	}
-
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	edid = (const struct edid *) edid_blob->data;
-	edid_get_mfg(edid, edid_vendor);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-
-	/* Analog bridges provide their own EDID */
-	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
-	    edid_vendor[2] != 'T')
-		return true;
-
-	return false;
-}
-
-static void chamelium_paint_xr24_pattern(uint32_t *data,
-					 size_t width, size_t height,
-					 size_t stride, size_t block_size)
-{
-	uint32_t colors[] = { 0xff000000,
-			      0xffff0000,
-			      0xff00ff00,
-			      0xff0000ff,
-			      0xffffffff };
-	unsigned i, j;
-
-	for (i = 0; i < height; i++)
-		for (j = 0; j < width; j++)
-			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
-}
-
-static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
-				    uint32_t fourcc, size_t block_size,
-				    struct igt_fb *fb)
-{
-	int fb_id;
-	void *ptr;
-
-	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
-
-	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
-			      DRM_FORMAT_MOD_LINEAR, fb);
-	igt_assert(fb_id > 0);
-
-	ptr = igt_fb_map_buffer(fb->fd, fb);
-	igt_assert(ptr);
-
-	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
-				     block_size);
-	igt_fb_unmap_buffer(fb, ptr);
-
-	return fb_id;
-}
-
-static void
-enable_output(data_t *data,
-	      struct chamelium_port *port,
-	      igt_output_t *output,
-	      drmModeModeInfo *mode,
-	      struct igt_fb *fb)
-{
-	igt_display_t *display = output->display;
-	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	drmModeConnector *connector = chamelium_port_get_connector(
-	    data->chamelium, port, false);
-
-	igt_assert(primary);
-
-	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
-	igt_plane_set_fb(primary, fb);
-	igt_output_override_mode(output, mode);
-
-	/* Clear any color correction values that might be enabled */
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
-	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
-		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
-
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
-		usleep(250000);
-
-	drmModeFreeConnector(connector);
-}
-
-static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
-{
-	enum pipe pipe;
-
-	for_each_pipe(display, pipe) {
-		if (igt_pipe_connector_valid(pipe, output)) {
-			return pipe;
-		}
-	}
-
-	igt_assert_f(false, "No pipe found for output %s\n",
-		     igt_output_name(output));
-}
-
-static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
-{
-	int fb_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, fb);
-
-	igt_assert(fb_id > 0);
-}
-
-static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
-								   port, false);
-	drmModeModeInfo mode;
-	igt_assert(&connector->modes[0] != NULL);
-	memcpy(&mode, &connector->modes[0], sizeof(mode));
-	drmModeFreeConnector(connector);
-	return mode;
-}
-
-static igt_output_t *get_output_for_port(data_t *data,
-					 struct chamelium_port *port)
-{
-	drmModeConnector *connector =
-		chamelium_port_get_connector(data->chamelium, port, true);
-	igt_output_t *output = igt_output_from_connector(&data->display,
-							 connector);
-	drmModeFreeConnector(connector);
-	igt_assert(output != NULL);
-	return output;
-}
-
-static const char test_hotplug_for_each_pipe_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug for each pipe with valid output";
-static void
-test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	enum pipe pipe;
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	chamelium_reset_state(&data->display,
-			      data->chamelium,
-			      port,
-			      data->ports,
-			      data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	/* Disconnect if any port got connected */
-	chamelium_unplug(data->chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port,
-			DRM_MODE_DISCONNECTED);
-
-	for_each_pipe(&data->display, pipe) {
-		igt_flush_uevents(mon);
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-		output = get_output_for_port(data, port);
-
-		/* If pipe is valid for output then set it */
-		if (igt_pipe_connector_valid(pipe, output)) {
-			igt_output_set_pipe(output, pipe);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-
-		chamelium_unplug(data->chamelium, port);
-		wait_for_connector_after_hotplug(data, mon, port,
-				DRM_MODE_DISCONNECTED);
-		igt_flush_uevents(mon);
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_basic_hotplug_desc[] =
-	"Check that we get uevents and updated connector status on "
-	"hotplug and unplug";
-static void
-test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
-	     enum test_modeset_mode modeset_mode)
-{
-	int i;
-	enum pipe pipe;
-	struct igt_fb fb = {0};
-	drmModeModeInfo mode;
-	struct udev_monitor *mon = igt_watch_uevents();
-	igt_output_t *output = get_output_for_port(data, port);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-
-	for (i = 0; i < toggle_count; i++) {
-		igt_flush_uevents(mon);
-
-		/* Check if we get a sysfs hotplug event */
-		chamelium_plug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_CONNECTED);
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF ||
-		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
-			if (i == 0) {
-				/* We can only get mode and pipe once we are connected */
-				output = get_output_for_port(data, port);
-				pipe = get_pipe_for_output(&data->display, output);
-				mode = get_mode_for_port(data->chamelium, port);
-				create_fb_for_mode(data, &fb, &mode);
-			}
-
-			igt_output_set_pipe(output, pipe);
-			enable_output(data, port, output, &mode, &fb);
-		}
-
-		/* Now check if we get a hotplug from disconnection */
-		chamelium_unplug(data->chamelium, port);
-
-		wait_for_connector_after_hotplug(data, mon, port,
-						 DRM_MODE_DISCONNECTED);
-
-		igt_flush_uevents(mon);
-
-		if (modeset_mode == TEST_MODESET_ON_OFF) {
-			igt_output_set_pipe(output, PIPE_NONE);
-			igt_display_commit2(&data->display, COMMIT_ATOMIC);
-		}
-	}
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static void set_edid(data_t *data, struct chamelium_port *port,
-		     enum igt_custom_edid_type edid)
-{
-	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
-}
-
-static const char igt_custom_edid_type_read_desc[] =
-	"Make sure the EDID exposed by KMS is the same as the screen's";
-static void
-igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	drmModePropertyBlobPtr edid_blob = NULL;
-	drmModeConnector *connector;
-	size_t raw_edid_size;
-	const struct edid *raw_edid;
-	uint64_t edid_blob_id;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_skip_on(check_analog_bridge(data, port));
-
-	connector = chamelium_port_get_connector(data->chamelium, port, true);
-	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
-					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
-					&edid_blob_id, NULL));
-	igt_assert(edid_blob_id != 0);
-	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
-						      edid_blob_id));
-
-	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
-	raw_edid_size = edid_get_size(raw_edid);
-	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
-
-	drmModeFreePropertyBlob(edid_blob);
-	drmModeFreeConnector(connector);
-}
-
-static void
-try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-		       enum igt_suspend_state state, enum igt_suspend_test test,
-		       struct udev_monitor *mon, bool connected)
-{
-	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
-						     DRM_MODE_CONNECTED;
-	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
-	int delay;
-	int p;
-
-	igt_flush_uevents(mon);
-
-	delay = igt_get_autoresume_delay(state) * 1000 / 2;
-
-	if (port) {
-		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
-					      !connected);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			port = data->ports[p];
-			chamelium_schedule_hpd_toggle(data->chamelium, port,
-						      delay, !connected);
-		}
-
-		port = NULL;
-	}
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(wait_for_hotplug(mon, &timeout));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	if (port) {
-		igt_assert_eq(chamelium_reprobe_connector(&data->display,
-							  data->chamelium,
-							  port),
-							  target_state);
-	} else {
-		for (p = 0; p < data->port_count; p++) {
-			drmModeConnection current_state;
-
-			port = data->ports[p];
-			/*
-			 * There could be as many hotplug events sent by
-			 * driver as connectors we scheduled an HPD toggle on
-			 * above, depending on timing. So if we're not seeing
-			 * the expected connector state try to wait for an HPD
-			 * event for each connector/port.
-			 */
-			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			if (p > 0 && current_state != target_state) {
-				igt_assert(wait_for_hotplug(mon, &timeout));
-				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
-			}
-
-			igt_assert_eq(current_state, target_state);
-		}
-
-		port = NULL;
-	}
-}
-
-static const char test_suspend_resume_hpd_desc[] =
-	"Toggle HPD during suspend, check that uevents are sent and connector "
-	"status is updated";
-static void
-test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
-			enum igt_suspend_state state,
-			enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, port, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_hpd_common_desc[] =
-	"Toggle HPD during suspend on all connectors, check that uevents are "
-	"sent and connector status is updated";
-static void
-test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
-			       enum igt_suspend_test test)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	struct chamelium_port *port;
-	int p;
-
-	for (p = 0; p < data->port_count; p++) {
-		port = data->ports[p];
-		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium, NULL,
-			      data->ports, data->port_count);
-
-	/* Make sure we notice new connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
-
-	/* Now make sure we notice disconnected connectors after resuming */
-	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_suspend_resume_edid_change_desc[] =
-	"Simulate a screen being unplugged and another screen being plugged "
-	"during suspend, check that a uevent is sent and connector status is "
-	"updated";
-static void
-test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
-				enum igt_suspend_state state,
-				enum igt_suspend_test test,
-				enum igt_custom_edid_type edid,
-				enum igt_custom_edid_type alt_edid)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-	bool link_status_failed[2][data->port_count];
-	int p;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Catch the event and flush all remaining ones. */
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_flush_uevents(mon);
-
-	/* First plug in the port */
-	set_edid(data, port, edid);
-	chamelium_plug(data->chamelium, port);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	/*
-	 * Change the edid before we suspend. On resume, the machine should
-	 * notice the EDID change and fire a hotplug event.
-	 */
-	set_edid(data, port, alt_edid);
-
-	get_connectors_link_status_failed(data, link_status_failed[0]);
-
-	igt_flush_uevents(mon);
-
-	igt_system_suspend_autoresume(state, test);
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
-
-	get_connectors_link_status_failed(data, link_status_failed[1]);
-
-	for (p = 0; p < data->port_count; p++)
-		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
-}
-
-static igt_output_t *
-prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	/* The chamelium's default EDID has a lot of resolutions, way more then
-	 * we need to test. Additionally the default EDID doesn't support HDMI
-	 * audio.
-	 */
-	set_edid(data, port, edid);
-
-	chamelium_plug(data->chamelium, port);
-	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
-					      port, DRM_MODE_CONNECTED);
-
-	igt_display_reset(display);
-
-	output = get_output_for_port(data, port);
-
-	/* Refresh pipe to update connected status */
-	igt_output_set_pipe(output, PIPE_NONE);
-
-	pipe = get_pipe_for_output(display, output);
-	igt_output_set_pipe(output, pipe);
-
-	return output;
-}
-
-static void do_test_display(data_t *data, struct chamelium_port *port,
-			    igt_output_t *output, drmModeModeInfo *mode,
-			    uint32_t fourcc, enum chamelium_check check,
-			    int count)
-{
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb frame_fb, fb;
-	int i, fb_id, captured_frame_count;
-	int frame_id;
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &fb);
-	igt_assert(fb_id > 0);
-
-	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
-				  DRM_FORMAT_MOD_LINEAR);
-	igt_assert(frame_id > 0);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-
-	enable_output(data, port, output, mode, &frame_fb);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		igt_crc_t *expected_crc;
-		igt_crc_t *crc;
-
-		/* We want to keep the display running for a little bit, since
-		 * there's always the potential the driver isn't able to keep
-		 * the display running properly for very long
-		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == count);
-
-		igt_debug("Captured %d frames\n", captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		for (i = 0; i < captured_frame_count; i++)
-			chamelium_assert_crc_eq_or_dump(data->chamelium,
-							expected_crc, &crc[i],
-							&fb, i);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_ANALOG ||
-		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		igt_assert(count == 1);
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-
-		if (check == CHAMELIUM_CHECK_ANALOG)
-			chamelium_crop_analog_frame(dump, mode->hdisplay,
-						    mode->vdisplay);
-
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	igt_remove_fb(data->drm_fd, &frame_fb);
-	igt_remove_fb(data->drm_fd, &fb);
-}
-
-static const char test_display_one_mode_desc[] =
-	"Pick the first mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_one_mode(data_t *data, struct chamelium_port *port,
-				  uint32_t fourcc, enum chamelium_check check,
-				  int count)
-{
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	igt_output_t *output;
-	igt_plane_t *primary;
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
-
-	mode = &connector->modes[0];
-	if (check == CHAMELIUM_CHECK_ANALOG) {
-		bool bridge = check_analog_bridge(data, port);
-
-		igt_assert(!(bridge && prune_vga_mode(data, mode)));
-	}
-
-	do_test_display(data, port, output, mode, fourcc, check, count);
-
-	drmModeFreeConnector(connector);
-}
-
-static const char test_display_all_modes_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then check captured frames are correct";
-static void test_display_all_modes(data_t *data, struct chamelium_port *port,
-				   uint32_t fourcc, enum chamelium_check check,
-				   int count)
-{
-	bool bridge;
-	int i, count_modes;
-
-	if (check == CHAMELIUM_CHECK_ANALOG)
-		bridge = check_analog_bridge(data, port);
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-		igt_require(igt_plane_has_format_mod(primary, fourcc,
-			    DRM_FORMAT_MOD_LINEAR));
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
-		    prune_vga_mode(data, mode))
-			continue;
-
-		do_test_display(data, port, output, mode, fourcc, check,
-				count);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-static const char test_display_frame_dump_desc[] =
-	"For each mode of the IGT base EDID, display and capture a few "
-	"frames, then download the captured frames and compare them "
-	"bit-by-bit to the sent ones";
-static void
-test_display_frame_dump(data_t *data, struct chamelium_port *port)
-{
-
-	int i, count_modes;
-
-	i = 0;
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		struct igt_fb fb;
-		struct chamelium_frame_dump *frame;
-		drmModeModeInfo *mode;
-		drmModeConnector *connector;
-		int fb_id, j;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port,
-							 false);
-		primary = igt_output_get_plane_type(output,
-						    DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Reading frame dumps from Chamelium...\n");
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
-		for (j = 0; j < 5; j++) {
-			frame = chamelium_read_captured_frame(data->chamelium,
-							      j);
-			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
-			chamelium_destroy_frame_dump(frame);
-		}
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
-
-static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
-		       drmModeModeInfo *mode)
-{
-	struct chamelium_video_params video_params = {0};
-	double mode_clock;
-	int mode_hsync_offset, mode_vsync_offset;
-	int mode_hsync_width, mode_vsync_width;
-	int mode_hsync_polarity, mode_vsync_polarity;
-
-	chamelium_port_get_video_params(chamelium, port, &video_params);
-
-	mode_clock = (double) mode->clock / 1000;
-
-	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
-		/* this is what chamelium understands as offsets for DP */
-		mode_hsync_offset = mode->htotal - mode->hsync_start;
-		mode_vsync_offset = mode->vtotal - mode->vsync_start;
-	} else {
-		/* and this is what they are for other connectors */
-		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
-		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
-	}
-
-	mode_hsync_width = mode->hsync_end - mode->hsync_start;
-	mode_vsync_width = mode->vsync_end - mode->vsync_start;
-
-	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-
-	igt_debug("Checking video mode:\n");
-	igt_debug("clock: got %f, expected %f ± %f%%\n",
-		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
-	igt_debug("hactive: got %d, expected %d\n",
-		  video_params.hactive, mode->hdisplay);
-	igt_debug("vactive: got %d, expected %d\n",
-		  video_params.vactive, mode->vdisplay);
-	igt_debug("hsync_offset: got %d, expected %d\n",
-		  video_params.hsync_offset, mode_hsync_offset);
-	igt_debug("vsync_offset: got %d, expected %d\n",
-		  video_params.vsync_offset, mode_vsync_offset);
-	igt_debug("htotal: got %d, expected %d\n",
-		  video_params.htotal, mode->htotal);
-	igt_debug("vtotal: got %d, expected %d\n",
-		  video_params.vtotal, mode->vtotal);
-	igt_debug("hsync_width: got %d, expected %d\n",
-		  video_params.hsync_width, mode_hsync_width);
-	igt_debug("vsync_width: got %d, expected %d\n",
-		  video_params.vsync_width, mode_vsync_width);
-	igt_debug("hsync_polarity: got %d, expected %d\n",
-		  video_params.hsync_polarity, mode_hsync_polarity);
-	igt_debug("vsync_polarity: got %d, expected %d\n",
-		  video_params.vsync_polarity, mode_vsync_polarity);
-
-	if (!isnan(video_params.clock)) {
-		igt_assert(video_params.clock >
-			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
-		igt_assert(video_params.clock <
-			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
-	}
-	igt_assert(video_params.hactive == mode->hdisplay);
-	igt_assert(video_params.vactive == mode->vdisplay);
-	igt_assert(video_params.hsync_offset == mode_hsync_offset);
-	igt_assert(video_params.vsync_offset == mode_vsync_offset);
-	igt_assert(video_params.htotal == mode->htotal);
-	igt_assert(video_params.vtotal == mode->vtotal);
-	igt_assert(video_params.hsync_width == mode_hsync_width);
-	igt_assert(video_params.vsync_width == mode_vsync_width);
-	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
-	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
-}
-
-static const char test_mode_timings_desc[] =
-	"For each mode of the IGT base EDID, perform a modeset and check the "
-	"mode detected by the Chamelium receiver matches the mode we set";
-static void test_mode_timings(data_t *data, struct chamelium_port *port)
-{
-	int i, count_modes;
-
-	i = 0;
-	igt_require(chamelium_supports_get_video_params(data->chamelium));
-	do {
-		igt_output_t *output;
-		igt_plane_t *primary;
-		drmModeConnector *connector;
-		drmModeModeInfo *mode;
-		int fb_id;
-		struct igt_fb fb;
-
-		/*
-		 * let's reset state each mode so we will get the
-		 * HPD pulses realibably
-		 */
-		igt_modeset_disable_all_outputs(&data->display);
-		chamelium_reset_state(&data->display, data->chamelium,
-				      port, data->ports, data->port_count);
-
-		/*
-		 * modes may change due to mode pruining and link issues, so we
-		 * need to refresh the connector
-		 */
-		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-		connector = chamelium_port_get_connector(data->chamelium, port, false);
-		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-		igt_assert(primary);
-
-		/* we may skip some modes due to above but that's ok */
-		count_modes = connector->count_modes;
-		if (i >= count_modes)
-			break;
-
-		mode = &connector->modes[i];
-
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    DRM_FORMAT_MOD_LINEAR,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		/* Trigger the FSM */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
-
-		check_mode(data->chamelium, port, mode);
-
-		igt_remove_fb(data->drm_fd, &fb);
-		drmModeFreeConnector(connector);
-	} while (++i < count_modes);
-}
-
-struct vic_mode {
-	int hactive, vactive;
-	int vrefresh; /* Hz */
-	uint32_t picture_ar;
-};
-
-/* Maps Video Identification Codes to a mode */
-static const struct vic_mode vic_modes[] = {
-	[16] = {
-		.hactive = 1920,
-		.vactive = 1080,
-		.vrefresh = 60,
-		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
-	},
-};
-
-/* Maps aspect ratios to their mode flag */
-static const uint32_t mode_ar_flags[] = {
-	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
-};
-
-static enum infoframe_avi_picture_aspect_ratio
-get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
-{
-	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
-	switch (aspect_ratio) {
-	case DRM_MODE_PICTURE_ASPECT_4_3:
-		return INFOFRAME_AVI_PIC_AR_4_3;
-	case DRM_MODE_PICTURE_ASPECT_16_9:
-		return INFOFRAME_AVI_PIC_AR_16_9;
-	default:
-		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
-	}
-}
-
-static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
-				 drmModeModeInfo *drm_mode)
-{
-	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
-
-	return vic_mode->hactive == drm_mode->hdisplay &&
-	       vic_mode->vactive == drm_mode->vdisplay &&
-	       vic_mode->vrefresh == drm_mode->vrefresh &&
-	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
-}
-
-static const char test_display_aspect_ratio_desc[] =
-	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
-	"check they include the relevant fields";
-static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	drmModeConnector *connector;
-	drmModeModeInfo *mode;
-	int fb_id, i;
-	struct igt_fb fb;
-	bool found, ok;
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_avi infoframe_avi;
-	uint8_t vic = 16; /* TODO: test more VICs */
-	const struct vic_mode *vic_mode;
-	uint32_t aspect_ratio;
-	enum infoframe_avi_picture_aspect_ratio frame_ar;
-
-	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	vic_mode = &vic_modes[vic];
-	aspect_ratio = vic_mode->picture_ar;
-
-	found = false;
-	igt_assert(connector->count_modes > 0);
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-
-		if (vic_mode_matches_drm(vic_mode, mode)) {
-			found = true;
-			break;
-		}
-	}
-	igt_assert_f(found,
-		     "Failed to find mode with the correct aspect ratio\n");
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
-						 CHAMELIUM_INFOFRAME_AVI);
-	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
-
-	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
-				 infoframe->payload, infoframe->payload_size);
-	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
-
-	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
-
-	igt_debug("Checking AVI InfoFrame\n");
-	igt_debug("Picture aspect ratio: got %d, expected %d\n",
-		  infoframe_avi.picture_aspect_ratio, frame_ar);
-	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
-		  infoframe_avi.vic, vic);
-
-	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
-	igt_assert(infoframe_avi.vic == vic);
-
-	chamelium_infoframe_destroy(infoframe);
-	igt_remove_fb(data->drm_fd, &fb);
-	drmModeFreeConnector(connector);
-}
-
-
-/* Playback parameters control the audio signal we synthesize and send */
-#define PLAYBACK_CHANNELS 2
-#define PLAYBACK_SAMPLES 1024
-
-/* Capture paremeters control the audio signal we receive */
-#define CAPTURE_SAMPLES 2048
-
-#define AUDIO_TIMEOUT 2000 /* ms */
-/* A streak of 3 gives confidence that the signal is good. */
-#define MIN_STREAK 3
-
-#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
-#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
-#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
-
-/* TODO: enable >48KHz rates, these are not reliable */
-static int test_sampling_rates[] = {
-	32000,
-	44100,
-	48000,
-	/* 88200, */
-	/* 96000, */
-	/* 176400, */
-	/* 192000, */
-};
-
-static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
-
-/* Test frequencies (Hz): a sine signal will be generated for each.
- *
- * Depending on the sampling rate chosen, it might not be possible to properly
- * detect the generated sine (see Nyquist–Shannon sampling theorem).
- * Frequencies that can't be reliably detected will be automatically pruned in
- * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
- * tested with a 192KHz sampling rate.
- */
-static int test_frequencies[] = {
-	300,
-	600,
-	1200,
-	10000,
-	80000,
-};
-
-static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
-
-static const snd_pcm_format_t test_formats[] = {
-	SND_PCM_FORMAT_S16_LE,
-	SND_PCM_FORMAT_S24_LE,
-	SND_PCM_FORMAT_S32_LE,
-};
-
-static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
-
-struct audio_state {
-	struct alsa *alsa;
-	struct chamelium *chamelium;
-	struct chamelium_port *port;
-	struct chamelium_stream *stream;
-
-	/* The capture format is only available after capture has started. */
-	struct {
-		snd_pcm_format_t format;
-		int channels;
-		int rate;
-	} playback, capture;
-
-	char *name;
-	struct audio_signal *signal; /* for frequencies test only */
-	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	size_t recv_pages;
-	int msec;
-
-	int dump_fd;
-	char *dump_path;
-
-	pthread_t thread;
-	atomic_bool run;
-	atomic_bool positive; /* for pulse test only */
-};
-
-static void audio_state_init(struct audio_state *state, data_t *data,
-			     struct alsa *alsa, struct chamelium_port *port,
-			     snd_pcm_format_t format, int channels, int rate)
-{
-	memset(state, 0, sizeof(*state));
-	state->dump_fd = -1;
-
-	state->alsa = alsa;
-	state->chamelium = data->chamelium;
-	state->port = port;
-
-	state->playback.format = format;
-	state->playback.channels = channels;
-	state->playback.rate = rate;
-
-	alsa_configure_output(alsa, format, channels, rate);
-
-	state->stream = chamelium_stream_init();
-	igt_assert_f(state->stream,
-		     "Failed to initialize Chamelium stream client\n");
-}
-
-static void audio_state_fini(struct audio_state *state)
-{
-	chamelium_stream_deinit(state->stream);
-	free(state->name);
-}
-
-static void *run_audio_thread(void *data)
-{
-	struct alsa *alsa = data;
-
-	alsa_run(alsa, -1);
-	return NULL;
-}
-
-static void audio_state_start(struct audio_state *state, const char *name)
-{
-	int ret;
-	bool ok;
-	size_t i, j;
-	enum chamelium_stream_realtime_mode stream_mode;
-	char dump_suffix[64];
-
-	free(state->name);
-	state->name = strdup(name);
-	state->recv_pages = 0;
-	state->msec = 0;
-
-	igt_debug("Starting %s test with playback format %s, "
-		  "sampling rate %d Hz and %d channels\n",
-		  name, snd_pcm_format_name(state->playback.format),
-		  state->playback.rate, state->playback.channels);
-
-	chamelium_start_capturing_audio(state->chamelium, state->port, false);
-
-	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
-	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
-	igt_assert_f(ok, "Failed to start streaming audio capture\n");
-
-	/* Start playing audio */
-	state->run = true;
-	ret = pthread_create(&state->thread, NULL,
-			     run_audio_thread, state->alsa);
-	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
-
-	/* The Chamelium device only supports this PCM format. */
-	state->capture.format = SND_PCM_FORMAT_S32_LE;
-
-	/* Only after we've started playing audio, we can retrieve the capture
-	 * format used by the Chamelium device. */
-	chamelium_get_audio_format(state->chamelium, state->port,
-				   &state->capture.rate,
-				   &state->capture.channels);
-	if (state->capture.rate == 0) {
-		igt_debug("Audio receiver doesn't indicate the capture "
-			 "sampling rate, assuming it's %d Hz\n",
-			 state->playback.rate);
-		state->capture.rate = state->playback.rate;
-	}
-
-	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
-					    state->channel_mapping);
-	/* Make sure we can capture all channels we send. */
-	for (i = 0; i < state->playback.channels; i++) {
-		ok = false;
-		for (j = 0; j < state->capture.channels; j++) {
-			if (state->channel_mapping[j] == i) {
-				ok = true;
-				break;
-			}
-		}
-		igt_assert_f(ok, "Cannot capture all channels\n");
-	}
-
-	if (igt_frame_dump_is_enabled()) {
-		snprintf(dump_suffix, sizeof(dump_suffix),
-			 "capture-%s-%s-%dch-%dHz",
-			 name, snd_pcm_format_name(state->playback.format),
-			 state->playback.channels, state->playback.rate);
-
-		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
-							      state->capture.rate,
-							      state->capture.channels,
-							      &state->dump_path);
-		igt_assert_f(state->dump_fd >= 0,
-			     "Failed to create audio dump file\n");
-	}
-}
-
-static void audio_state_receive(struct audio_state *state,
-				int32_t **recv, size_t *recv_len)
-{
-	bool ok;
-	size_t page_count;
-	size_t recv_size;
-
-	ok = chamelium_stream_receive_realtime_audio(state->stream,
-						     &page_count,
-						     recv, recv_len);
-	igt_assert_f(ok, "Failed to receive audio from stream server\n");
-
-	state->msec = state->recv_pages * *recv_len
-		      / (double) state->capture.channels
-		      / (double) state->capture.rate * 1000;
-	state->recv_pages++;
-
-	if (state->dump_fd >= 0) {
-		recv_size = *recv_len * sizeof(int32_t);
-		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
-			     "Failed to write to audio dump file\n");
-	}
-}
-
-static void audio_state_stop(struct audio_state *state, bool success)
-{
-	bool ok;
-	int ret;
-	struct chamelium_audio_file *audio_file;
-	enum igt_log_level log_level;
-
-	igt_debug("Stopping audio playback\n");
-	state->run = false;
-	ret = pthread_join(state->thread, NULL);
-	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
-
-	ok = chamelium_stream_stop_realtime_audio(state->stream);
-	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
-
-	audio_file = chamelium_stop_capturing_audio(state->chamelium,
-						    state->port);
-	if (audio_file) {
-		igt_debug("Audio file saved on the Chamelium in %s\n",
-			  audio_file->path);
-		chamelium_destroy_audio_file(audio_file);
-	}
-
-	if (state->dump_fd >= 0) {
-		close(state->dump_fd);
-		state->dump_fd = -1;
-
-		if (success) {
-			/* Test succeeded, no need to keep the captured data */
-			unlink(state->dump_path);
-		} else
-			igt_debug("Saved captured audio data to %s\n",
-				  state->dump_path);
-		free(state->dump_path);
-		state->dump_path = NULL;
-	}
-
-	if (success)
-		log_level = IGT_LOG_DEBUG;
-	else
-		log_level = IGT_LOG_CRITICAL;
-
-	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
-		"sampling rate %d Hz and %d channels: %s\n",
-		state->name, snd_pcm_format_name(state->playback.format),
-		state->playback.rate, state->playback.channels,
-		success ? "ALL GREEN" : "FAILED");
-
-}
-
-static void check_audio_infoframe(struct audio_state *state)
-{
-	struct chamelium_infoframe *infoframe;
-	struct infoframe_audio infoframe_audio;
-	struct infoframe_audio expected = {0};
-	bool ok;
-
-	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
-		igt_debug("Skipping audio InfoFrame check: "
-			  "Chamelium board doesn't support GetLastInfoFrame\n");
-		return;
-	}
-
-	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
-	expected.channel_count = state->playback.channels;
-	expected.sampling_freq = state->playback.rate;
-	expected.sample_size = snd_pcm_format_width(state->playback.format);
-
-	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
-						 CHAMELIUM_INFOFRAME_AUDIO);
-	if (infoframe == NULL && state->playback.channels <= 2) {
-		/* Audio InfoFrames are optional for mono and stereo audio */
-		igt_debug("Skipping audio InfoFrame check: "
-			  "no InfoFrame received\n");
-		return;
-	}
-	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
-
-	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
-				   infoframe->payload, infoframe->payload_size);
-	chamelium_infoframe_destroy(infoframe);
-	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
-
-	igt_debug("Checking audio InfoFrame:\n");
-	igt_debug("coding_type: got %d, expected %d\n",
-		  infoframe_audio.coding_type, expected.coding_type);
-	igt_debug("channel_count: got %d, expected %d\n",
-		  infoframe_audio.channel_count, expected.channel_count);
-	igt_debug("sampling_freq: got %d, expected %d\n",
-		  infoframe_audio.sampling_freq, expected.sampling_freq);
-	igt_debug("sample_size: got %d, expected %d\n",
-		  infoframe_audio.sample_size, expected.sample_size);
-
-	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
-		igt_assert(infoframe_audio.coding_type == expected.coding_type);
-	if (infoframe_audio.channel_count >= 0)
-		igt_assert(infoframe_audio.channel_count == expected.channel_count);
-	if (infoframe_audio.sampling_freq >= 0)
-		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
-	if (infoframe_audio.sample_size >= 0)
-		igt_assert(infoframe_audio.sample_size == expected.sample_size);
-}
-
-static int
-audio_output_frequencies_callback(void *data, void *buffer, int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	audio_signal_fill(state->signal, tmp, samples);
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool test_audio_frequencies(struct audio_state *state)
-{
-	int freq, step;
-	int32_t *recv, *buf;
-	double *channel;
-	size_t i, j, streak;
-	size_t recv_len, buf_len, buf_cap, channel_len;
-	bool success;
-	int capture_chan;
-
-	state->signal = audio_signal_init(state->playback.channels,
-					  state->playback.rate);
-	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
-
-	/* We'll choose different frequencies per channel to make sure they are
-	 * independent from each other. To do so, we'll add a different offset
-	 * to the base frequencies for each channel. We need to choose a big
-	 * enough offset so that we're sure to detect mixed up channels. We
-	 * choose an offset of two 2 bins in the final FFT to enforce a clear
-	 * difference.
-	 *
-	 * Note that we assume capture_rate == playback_rate. We'll assert this
-	 * later on. We cannot retrieve the capture rate before starting
-	 * playing audio, so we don't really have the choice.
-	 */
-	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
-	for (i = 0; i < test_frequencies_count; i++) {
-		for (j = 0; j < state->playback.channels; j++) {
-			freq = test_frequencies[i] + j * step;
-			audio_signal_add_frequency(state->signal, freq, j);
-		}
-	}
-	audio_signal_synthesize(state->signal);
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_frequencies_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	audio_state_start(state, "frequencies");
-
-	igt_assert_f(state->capture.rate == state->playback.rate,
-		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
-		     state->capture.rate, state->playback.rate);
-
-	/* Needs to be a multiple of 128, because that's the number of samples
-	 * we get per channel each time we receive an audio page from the
-	 * Chamelium device.
-	 *
-	 * Additionally, this value needs to be high enough to guarantee we
-	 * capture a full period of each sine we generate. If we capture 2048
-	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
-	 * sines. For lower sampling rates, the capture duration will be
-	 * longer.
-	 */
-	channel_len = CAPTURE_SAMPLES;
-	channel = malloc(sizeof(double) * channel_len);
-
-	buf_cap = state->capture.channels * channel_len;
-	buf = malloc(sizeof(int32_t) * buf_cap);
-	buf_len = 0;
-
-	recv = NULL;
-	recv_len = 0;
-
-	success = false;
-	streak = 0;
-	while (!success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
-		buf_len += recv_len;
-
-		if (buf_len < buf_cap)
-			continue;
-		igt_assert(buf_len == buf_cap);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (j = 0; j < state->playback.channels; j++) {
-			capture_chan = state->channel_mapping[j];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", j, capture_chan);
-
-			audio_extract_channel_s32_le(channel, channel_len,
-						     buf, buf_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			if (audio_signal_detect(state->signal,
-						state->capture.rate, j,
-						channel, channel_len))
-				streak++;
-			else
-				streak = 0;
-		}
-
-		buf_len = 0;
-
-		success = streak == MIN_STREAK * state->playback.channels;
-	}
-
-	audio_state_stop(state, success);
-
-	free(recv);
-	free(buf);
-	free(channel);
-	audio_signal_fini(state->signal);
-
-	check_audio_infoframe(state);
-
-	return success;
-}
-
-static int audio_output_flatline_callback(void *data, void *buffer,
-					     int samples)
-{
-	struct audio_state *state = data;
-	double *tmp;
-	size_t len, i;
-
-	len = samples * state->playback.channels;
-	tmp = malloc(len * sizeof(double));
-	for (i = 0; i < len; i++)
-		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
-	audio_convert_to(buffer, tmp, len, state->playback.format);
-	free(tmp);
-
-	return state->run ? 0 : -1;
-}
-
-static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
-{
-	double expected, min, max;
-	size_t i;
-	bool ok;
-
-	min = max = NAN;
-	for (i = 0; i < buf_len; i++) {
-		if (isnan(min) || buf[i] < min)
-			min = buf[i];
-		if (isnan(max) || buf[i] > max)
-			max = buf[i];
-	}
-
-	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
-	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
-	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
-	if (ok)
-		igt_debug("Flatline wave amplitude detected\n");
-	else
-		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
-			  min, max);
-	return ok;
-}
-
-static ssize_t detect_falling_edge(double *buf, size_t buf_len)
-{
-	size_t i;
-
-	for (i = 0; i < buf_len; i++) {
-		if (buf[i] < 0)
-			return i;
-	}
-
-	return -1;
-}
-
-/** test_audio_flatline:
- *
- * Send a constant value (one positive, then a negative one) and check that:
- *
- * - The amplitude of the flatline is correct
- * - All channels switch from a positive signal to a negative one at the same
- *   time (ie. all channels are aligned)
- */
-static bool test_audio_flatline(struct audio_state *state)
-{
-	bool success, amp_success, align_success;
-	int32_t *recv;
-	size_t recv_len, i, channel_len;
-	ssize_t j;
-	int streak, capture_chan;
-	double *channel;
-	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
-
-	alsa_register_output_callback(state->alsa,
-				      audio_output_flatline_callback, state,
-				      PLAYBACK_SAMPLES);
-
-	/* Start by sending a positive signal */
-	state->positive = true;
-
-	audio_state_start(state, "flatline");
-
-	for (i = 0; i < state->playback.channels; i++)
-		falling_edges[i] = -1;
-
-	recv = NULL;
-	recv_len = 0;
-	amp_success = false;
-	streak = 0;
-	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
-		audio_state_receive(state, &recv, &recv_len);
-
-		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
-
-		for (i = 0; i < state->playback.channels; i++) {
-			capture_chan = state->channel_mapping[i];
-			igt_assert(capture_chan >= 0);
-			igt_debug("Processing channel %zu (captured as "
-				  "channel %d)\n", i, capture_chan);
-
-			channel_len = audio_extract_channel_s32_le(NULL, 0,
-								   recv, recv_len,
-								   state->capture.channels,
-								   capture_chan);
-			channel = malloc(channel_len * sizeof(double));
-			audio_extract_channel_s32_le(channel, channel_len,
-						     recv, recv_len,
-						     state->capture.channels,
-						     capture_chan);
-
-			/* Check whether the amplitude is fine */
-			if (detect_flatline_amplitude(channel, channel_len,
-						      state->positive))
-				streak++;
-			else
-				streak = 0;
-
-			/* If we're now sending a negative signal, detect the
-			 * falling edge */
-			j = detect_falling_edge(channel, channel_len);
-			if (!state->positive && j >= 0) {
-				falling_edges[i] = recv_len * state->recv_pages
-						   + j;
-			}
-
-			free(channel);
-		}
-
-		amp_success = streak == MIN_STREAK * state->playback.channels;
-
-		if (amp_success && state->positive) {
-			/* Switch to a negative signal after we've detected the
-			 * positive one. */
-			state->positive = false;
-			amp_success = false;
-			streak = 0;
-			igt_debug("Switching to negative square wave\n");
-		}
-	}
-
-	/* Check alignment between all channels by comparing the index of the
-	 * falling edge. */
-	align_success = true;
-	for (i = 0; i < state->playback.channels; i++) {
-		if (falling_edges[i] < 0) {
-			igt_critical("Falling edge not detected for channel %zu\n",
-				     i);
-			align_success = false;
-			continue;
-		}
-
-		if (abs(falling_edges[0] - falling_edges[i]) >
-		    FLATLINE_ALIGN_ACCURACY) {
-			igt_critical("Channel alignment mismatch: "
-				     "channel 0 has a falling edge at index %d "
-				     "while channel %zu has index %d\n",
-				     falling_edges[0], i, falling_edges[i]);
-			align_success = false;
-		}
-	}
-
-	success = amp_success && align_success;
-	audio_state_stop(state, success);
-
-	free(recv);
-
-	return success;
-}
-
-static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
-				      int channels, int sampling_rate)
-{
-	if (!alsa_test_output_configuration(alsa, format, channels,
-					    sampling_rate)) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because at least one of the "
-			  "selected output devices doesn't support this "
-			  "configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	/* TODO: the Chamelium device sends a malformed signal for some audio
-	 * configurations. See crbug.com/950917 */
-	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
-			channels > 2) {
-		igt_debug("Skipping test with format %s, sampling rate %d Hz "
-			  "and %d channels because the Chamelium device "
-			  "doesn't support this configuration\n",
-			  snd_pcm_format_name(format),
-			  sampling_rate, channels);
-		return false;
-	}
-	return true;
-}
-
-static const char test_display_audio_desc[] =
-	"Playback various audio signals with various audio formats/rates, "
-	"capture them and check they are correct";
-static void
-test_display_audio(data_t *data, struct chamelium_port *port,
-		   const char *audio_device, enum igt_custom_edid_type edid)
-{
-	bool run, success;
-	struct alsa *alsa;
-	int ret;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j;
-	int channels, sampling_rate;
-	snd_pcm_format_t format;
-	struct audio_state state;
-
-	igt_require(alsa_has_exclusive_access());
-
-	/* Old Chamelium devices need an update for DisplayPort audio and
-	 * chamelium_get_audio_format support. */
-	igt_require(chamelium_has_audio_support(data->chamelium, port));
-
-	alsa = alsa_init();
-	igt_assert(alsa);
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because the receiver won't try to receive audio if
-	 * it doesn't receive video. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	run = false;
-	success = true;
-	for (i = 0; i < test_sampling_rates_count; i++) {
-		for (j = 0; j < test_formats_count; j++) {
-			ret = alsa_open_output(alsa, audio_device);
-			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
-
-			/* TODO: playback on all 8 available channels (this
-			 * isn't supported by Chamelium devices yet, see
-			 * https://crbug.com/950917) */
-			format = test_formats[j];
-			channels = PLAYBACK_CHANNELS;
-			sampling_rate = test_sampling_rates[i];
-
-			if (!check_audio_configuration(alsa, format, channels,
-						       sampling_rate))
-				continue;
-
-			run = true;
-
-			audio_state_init(&state, data, alsa, port,
-					 format, channels, sampling_rate);
-			success &= test_audio_frequencies(&state);
-			success &= test_audio_flatline(&state);
-			audio_state_fini(&state);
-
-			alsa_close_output(alsa);
-		}
-	}
-
-	/* Make sure we tested at least one frequency and format. */
-	igt_assert(run);
-	/* Make sure all runs were successful. */
-	igt_assert(success);
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-
-	free(alsa);
-}
-
-static const char test_display_audio_edid_desc[] =
-	"Plug a connector with an EDID suitable for audio, check ALSA's "
-	"EDID-Like Data reports the correct audio parameters";
-static void
-test_display_audio_edid(data_t *data, struct chamelium_port *port,
-			enum igt_custom_edid_type edid)
-{
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id;
-	struct eld_entry eld;
-	struct eld_sad *sad;
-
-	igt_require(eld_is_supported());
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	output = prepare_output(data, port, edid);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	/* Enable the output because audio cannot be played on inactive
-	 * connectors. */
-	igt_assert(connector->count_modes > 0);
-	mode = &connector->modes[0];
-
-	fb_id = igt_create_color_pattern_fb(data->drm_fd,
-					    mode->hdisplay, mode->vdisplay,
-					    DRM_FORMAT_XRGB8888,
-					    DRM_FORMAT_MOD_LINEAR,
-					    0, 0, 0, &fb);
-	igt_assert(fb_id > 0);
-
-	enable_output(data, port, output, mode, &fb);
-
-	igt_assert(eld_get_igt(&eld));
-	igt_assert(eld.sads_len == 1);
-
-	sad = &eld.sads[0];
-	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
-	igt_assert(sad->channels == 2);
-	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
-		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
-	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
-		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
-
-	igt_remove_fb(data->drm_fd, &fb);
-
-	drmModeFreeConnector(connector);
-}
-
-static void randomize_plane_stride(data_t *data,
-				   uint32_t width, uint32_t height,
-				   uint32_t format, uint64_t modifier,
-				   size_t *stride)
-{
-	size_t stride_min;
-	uint32_t max_tile_w = 4, tile_w, tile_h;
-	int i;
-	struct igt_fb dummy;
-
-	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
-
-	/* Randomize the stride to less than twice the minimum. */
-	*stride = (rand() % stride_min) + stride_min;
-
-	/*
-	 * Create a dummy FB to determine bpp for each plane, and calculate
-	 * the maximum tile width from that.
-	 */
-	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
-	for (i = 0; i < dummy.num_planes; i++) {
-		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
-
-		if (tile_w > max_tile_w)
-			max_tile_w = tile_w;
-	}
-	igt_remove_fb(data->drm_fd, &dummy);
-
-	/*
-	 * Pixman requires the stride to be aligned to 32-bits, which is
-	 * reflected in the initial value of max_tile_w and the hw
-	 * may require a multiple of tile width, choose biggest of the 2.
-	 */
-	*stride = ALIGN(*stride, max_tile_w);
-}
-
-static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
-				  uint32_t height, uint32_t format,
-				  uint64_t *modifier)
-{
-	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
-		/* Randomize the column height to less than twice the minimum. */
-		size_t column_height = (rand() % height) + height;
-
-		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
-			  column_height);
-
-		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
-	}
-}
-
-static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
-				  drmModeModeInfo *mode,
-				  uint32_t *width, uint32_t *height,
-				  uint32_t *format, uint64_t *modifier,
-				  bool allow_yuv)
-{
-	int min_dim;
-	uint32_t idx[plane->format_mod_count];
-	unsigned int count = 0;
-	unsigned int i;
-
-	/* First pass to count the supported formats. */
-	for (i = 0; i < plane->format_mod_count; i++)
-		if (igt_fb_supported_format(plane->formats[i]) &&
-		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
-			idx[count++] = i;
-
-	igt_assert(count > 0);
-
-	i = idx[rand() % count];
-	*format = plane->formats[i];
-	*modifier = plane->modifiers[i];
-
-	update_tiled_modifier(plane, *width, *height, *format, modifier);
-
-	/*
-	 * Randomize width and height in the mode dimensions range.
-	 *
-	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
-	 * least min_dim, because src_w = width - (rand % w / 2).
-	 *
-	 * Use a minimum dimension of 16 for YUV, because planar YUV
-	 * subsamples the UV plane.
-	 */
-	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
-
-	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
-	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
-}
-
-static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
-			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
-			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
-			    struct igt_fb *fb)
-{
-	igt_plane_set_fb(plane, fb);
-
-	igt_plane_set_position(plane, crtc_x, crtc_y);
-	igt_plane_set_size(plane, crtc_w, crtc_h);
-
-	igt_fb_set_position(fb, plane, src_x, src_y);
-	igt_fb_set_size(fb, plane, src_w, src_h);
-}
-
-static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
-					drmModeModeInfo *mode,
-					struct igt_fb *fb,
-					uint32_t *src_w, uint32_t *src_h,
-					uint32_t *src_x, uint32_t *src_y,
-					uint32_t *crtc_w, uint32_t *crtc_h,
-					int32_t *crtc_x, int32_t *crtc_y,
-					bool allow_scaling)
-{
-	bool is_yuv = igt_format_is_yuv(fb->drm_format);
-	uint32_t width = fb->width, height = fb->height;
-	double ratio;
-	int ret;
-
-	/* Randomize source offset in the first half of the original size. */
-	*src_x = rand() % (width / 2);
-	*src_y = rand() % (height / 2);
-
-	/* The source size only includes the active source area. */
-	*src_w = width - *src_x;
-	*src_h = height - *src_y;
-
-	if (allow_scaling) {
-		*crtc_w = (rand() % mode->hdisplay) + 1;
-		*crtc_h = (rand() % mode->vdisplay) + 1;
-
-		/*
-		 * Don't bother with scaling if dimensions are quite close in
-		 * order to get non-scaling cases more frequently. Also limit
-		 * scaling to 3x to avoid agressive filtering that makes
-		 * comparison less reliable, and don't go above 2x downsampling
-		 * to avoid possible hw limitations.
-		 */
-
-		ratio = ((double) *crtc_w / *src_w);
-		if (ratio < 0.5)
-			*src_w = *crtc_w * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_w = *src_w;
-		else if (ratio > 3.0)
-			*crtc_w = *src_w * 3;
-
-		ratio = ((double) *crtc_h / *src_h);
-		if (ratio < 0.5)
-			*src_h = *crtc_h * 2;
-		else if (ratio > 0.8 && ratio < 1.2)
-			*crtc_h = *src_h;
-		else if (ratio > 3.0)
-			*crtc_h = *src_h * 3;
-	} else {
-		*crtc_w = *src_w;
-		*crtc_h = *src_h;
-	}
-
-	if (*crtc_w != *src_w || *crtc_h != *src_h) {
-		/*
-		 * When scaling is involved, make sure to not go off-bounds or
-		 * scaled clipping may result in decimal dimensions, that most
-		 * drivers don't support.
-		 */
-		if (*crtc_w < mode->hdisplay)
-			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
-		else
-			*crtc_x = 0;
-
-		if (*crtc_h < mode->vdisplay)
-			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
-		else
-			*crtc_y = 0;
-	} else {
-		/*
-		 * Randomize the on-crtc position and allow the plane to go
-		 * off-display by less than half of its on-crtc dimensions.
-		 */
-		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
-		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
-	}
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
-			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
-	ret = igt_display_try_commit_atomic(&data->display,
-					    DRM_MODE_ATOMIC_TEST_ONLY |
-					    DRM_MODE_ATOMIC_ALLOW_MODESET,
-					    NULL);
-	if (!ret)
-		return;
-
-	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
-	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
-
-	/* Make YUV coordinates a multiple of 2 and retry the math. */
-	if (is_yuv) {
-		*src_x &= ~1;
-		*src_y &= ~1;
-		*src_w &= ~1;
-		*src_h &= ~1;
-		/* To handle 1:1 scaling, clear crtc_w/h too. */
-		*crtc_w &= ~1;
-		*crtc_h &= ~1;
-
-		if (*crtc_x < 0 && (*crtc_x & 1))
-			(*crtc_x)++;
-		else
-			*crtc_x &= ~1;
-
-		/* If negative, round up to 0 instead of down */
-		if (*crtc_y < 0 && (*crtc_y & 1))
-			(*crtc_y)++;
-		else
-			*crtc_y &= ~1;
-
-		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-				*crtc_h, *crtc_x, *crtc_y, fb);
-		ret = igt_display_try_commit_atomic(&data->display,
-						DRM_MODE_ATOMIC_TEST_ONLY |
-						DRM_MODE_ATOMIC_ALLOW_MODESET,
-						NULL);
-		if (!ret)
-			return;
-	}
-
-	igt_assert(!ret || allow_scaling);
-	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
-		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
-
-	*crtc_w = *src_w;
-	*crtc_h = *src_h;
-
-	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
-			*crtc_h, *crtc_x, *crtc_y, fb);
-	igt_display_commit_atomic(&data->display,
-				  DRM_MODE_ATOMIC_TEST_ONLY |
-				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
-}
-
-static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
-			     uint32_t src_w, uint32_t src_h,
-			     uint32_t src_x, uint32_t src_y,
-			     uint32_t crtc_w, uint32_t crtc_h,
-			     int32_t crtc_x, int32_t crtc_y,
-			     struct igt_fb *fb)
-{
-	cairo_surface_t *surface;
-	cairo_surface_t *clipped_surface;
-	cairo_t *cr;
-
-	surface = igt_get_cairo_surface(data->drm_fd, fb);
-
-	if (src_x || src_y) {
-		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
-							     src_w, src_h);
-
-		cr = cairo_create(clipped_surface);
-
-		cairo_translate(cr, -1. * src_x, -1. * src_y);
-
-		cairo_set_source_surface(cr, surface, 0, 0);
-
-		cairo_paint(cr);
-		cairo_surface_flush(clipped_surface);
-
-		cairo_destroy(cr);
-	} else {
-		clipped_surface = surface;
-	}
-
-	cr = cairo_create(result);
-
-	cairo_translate(cr, crtc_x, crtc_y);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_scale(cr, (double) crtc_w / src_w,
-			    (double) crtc_h / src_h);
-	}
-
-	cairo_set_source_surface(cr, clipped_surface, 0, 0);
-	cairo_surface_destroy(clipped_surface);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		cairo_pattern_set_filter(cairo_get_source(cr),
-					 CAIRO_FILTER_BILINEAR);
-		cairo_pattern_set_extend(cairo_get_source(cr),
-					 CAIRO_EXTEND_NONE);
-	}
-
-	cairo_paint(cr);
-	cairo_surface_flush(result);
-
-	cairo_destroy(cr);
-}
-
-static void prepare_randomized_plane(data_t *data,
-				     drmModeModeInfo *mode,
-				     igt_plane_t *plane,
-				     struct igt_fb *overlay_fb,
-				     unsigned int index,
-				     cairo_surface_t *result_surface,
-				     bool allow_scaling, bool allow_yuv)
-{
-	struct igt_fb pattern_fb;
-	uint32_t overlay_fb_w, overlay_fb_h;
-	uint32_t overlay_src_w, overlay_src_h;
-	uint32_t overlay_src_x, overlay_src_y;
-	int32_t overlay_crtc_x, overlay_crtc_y;
-	uint32_t overlay_crtc_w, overlay_crtc_h;
-	uint32_t format;
-	uint64_t modifier;
-	size_t stride;
-	bool tiled;
-	int fb_id;
-
-	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
-			      &format, &modifier, allow_yuv);
-
-	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
-	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
-		  index, overlay_fb_w, overlay_fb_h,
-		  igt_format_str(format), tiled ? "tiled" : "linear");
-
-	/* Get a pattern framebuffer for the overlay plane. */
-	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
-					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
-			       format, modifier, &stride);
-
-	igt_debug("Plane %d: stride %ld\n", index, stride);
-
-	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
-					   modifier, stride);
-	igt_assert(fb_id > 0);
-
-	randomize_plane_coordinates(data, plane, mode, overlay_fb,
-				    &overlay_src_w, &overlay_src_h,
-				    &overlay_src_x, &overlay_src_y,
-				    &overlay_crtc_w, &overlay_crtc_h,
-				    &overlay_crtc_x, &overlay_crtc_y,
-				    allow_scaling);
-
-	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
-		  overlay_src_w, overlay_src_h);
-	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
-		  overlay_src_x, overlay_src_y);
-	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
-		  overlay_crtc_w, overlay_crtc_h);
-	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
-		  overlay_crtc_x, overlay_crtc_y);
-
-	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
-			 overlay_src_x, overlay_src_y,
-			 overlay_crtc_w, overlay_crtc_h,
-			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
-
-	/* Remove the original pattern framebuffer. */
-	igt_remove_fb(data->drm_fd, &pattern_fb);
-}
-
-static const char test_display_planes_random_desc[] =
-	"Setup a few overlay planes with random parameters, capture the frame "
-	"and check it matches the expected output";
-static void test_display_planes_random(data_t *data,
-				       struct chamelium_port *port,
-				       enum chamelium_check check)
-{
-	igt_output_t *output;
-	drmModeModeInfo *mode;
-	igt_plane_t *primary_plane;
-	struct igt_fb primary_fb;
-	struct igt_fb result_fb;
-	struct igt_fb *overlay_fbs;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	unsigned int overlay_planes_max = 0;
-	unsigned int overlay_planes_count;
-	cairo_surface_t *result_surface;
-	int captured_frame_count;
-	bool allow_scaling;
-	bool allow_yuv;
-	unsigned int i;
-	unsigned int fb_id;
-
-	switch (check) {
-	case CHAMELIUM_CHECK_CRC:
-		allow_scaling = false;
-		allow_yuv = false;
-		break;
-	case CHAMELIUM_CHECK_CHECKERBOARD:
-		allow_scaling = true;
-		allow_yuv = true;
-		break;
-	default:
-		igt_assert(false);
-	}
-
-	srand(time(NULL));
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	/* Find the connector and pipe. */
-	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
-
-	mode = igt_output_get_mode(output);
-
-	/* Get a framebuffer for the primary plane. */
-	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary_plane);
-
-	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
-					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
-	igt_assert(fb_id > 0);
-
-	/* Get a framebuffer for the cairo composition result. */
-	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
-			      mode->vdisplay, DRM_FORMAT_XRGB8888,
-			      DRM_FORMAT_MOD_LINEAR, &result_fb);
-	igt_assert(fb_id > 0);
-
-	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
-
-	/* Paint the primary framebuffer on the result surface. */
-	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
-			 &primary_fb);
-
-	/* Configure the primary plane. */
-	igt_plane_set_fb(primary_plane, &primary_fb);
-
-	overlay_planes_max =
-		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
-
-	/* Limit the number of planes to a reasonable scene. */
-	overlay_planes_max = min(overlay_planes_max, 4u);
-
-	overlay_planes_count = (rand() % overlay_planes_max) + 1;
-	igt_debug("Using %d overlay planes\n", overlay_planes_count);
-
-	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
-
-	for (i = 0; i < overlay_planes_count; i++) {
-		struct igt_fb *overlay_fb = &overlay_fbs[i];
-		igt_plane_t *plane =
-			igt_output_get_plane_type_index(output,
-							DRM_PLANE_TYPE_OVERLAY,
-							i);
-		igt_assert(plane);
-
-		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
-					 result_surface, allow_scaling,
-					 allow_yuv);
-	}
-
-	cairo_surface_destroy(result_surface);
-
-	if (check == CHAMELIUM_CHECK_CRC)
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&result_fb);
-
-	igt_display_commit2(&data->display, COMMIT_ATOMIC);
-
-	if (check == CHAMELIUM_CHECK_CRC) {
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		igt_assert(captured_frame_count == 1);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium,
-						expected_crc, crc,
-						&result_fb, 0);
-
-		free(expected_crc);
-		free(crc);
-	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
-		struct chamelium_frame_dump *dump;
-
-		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
-						  0, 0);
-		chamelium_assert_frame_match_or_dump(data->chamelium, port,
-						     dump, &result_fb, check);
-		chamelium_destroy_frame_dump(dump);
-	}
-
-	for (i = 0; i < overlay_planes_count; i++)
-		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
-
-	free(overlay_fbs);
-
-	igt_remove_fb(data->drm_fd, &primary_fb);
-	igt_remove_fb(data->drm_fd, &result_fb);
-}
-
-static const char test_hpd_without_ddc_desc[] =
-	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
-static void
-test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
-{
-	struct udev_monitor *mon = igt_watch_uevents();
-
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-	igt_flush_uevents(mon);
-
-	/* Disable the DDC on the connector and make sure we still get a
-	 * hotplug
-	 */
-	chamelium_port_set_ddc_state(data->chamelium, port, false);
-	chamelium_plug(data->chamelium, port);
-
-	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
-	igt_assert_eq(chamelium_reprobe_connector(&data->display,
-						  data->chamelium, port),
-						  DRM_MODE_CONNECTED);
-
-	igt_cleanup_uevents(mon);
-}
-
-static const char test_hpd_storm_detect_desc[] =
-	"Trigger a series of hotplugs in a very small timeframe to simulate a"
-	"bad cable, check the kernel falls back to polling to avoid a hotplug "
-	"storm";
-static void
-test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
-{
-	struct udev_monitor *mon;
-	int count = 0;
-
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 1);
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-	igt_assert(igt_hpd_storm_detected(data->drm_fd));
-
-	mon = igt_watch_uevents();
-	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
-
-	/*
-	 * Polling should have been enabled by the HPD storm at this point,
-	 * so we should only get at most 1 hotplug event
-	 */
-	igt_until_timeout(5)
-		count += igt_hotplug_detected(mon, 1);
-	igt_assert_lt(count, 2);
-
-	igt_cleanup_uevents(mon);
-	igt_hpd_storm_reset(data->drm_fd);
-}
-
-static const char test_hpd_storm_disable_desc[] =
-	"Disable HPD storm detection, trigger a storm and check the kernel "
-	"doesn't detect one";
-static void
-test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
-{
-	igt_require_hpd_storm_ctl(data->drm_fd);
-	igt_modeset_disable_all_outputs(&data->display);
-	chamelium_reset_state(&data->display, data->chamelium,
-			      port, data->ports, data->port_count);
-
-	igt_hpd_storm_set_threshold(data->drm_fd, 0);
-	chamelium_fire_hpd_pulses(data->chamelium, port,
-				  width, 10);
-	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
-
-	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,
-				   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;
-
-		monitor_edid *edid = &edids_list[i];
-		igt_info("Testing out the EDID for %s\n",
-			 monitor_edid_get_name(edid));
-
-		/* Getting and Setting the EDID on Chamelium. */
-		chamelium_edid =
-			get_chameleon_edid_from_monitor_edid(chamelium, 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);
-}
-
-static const char igt_edid_resolution_list_desc[] =
-	"Get an EDID with many modes of different configurations, set them on the screen and check the"
-	" screen resolution matches the mode resolution.";
-
-static void edid_resolution_list(data_t *data, struct chamelium_port *port)
-{
-	struct chamelium *chamelium = data->chamelium;
-	struct udev_monitor *mon = igt_watch_uevents();
-	drmModeConnector *connector;
-	drmModeModeInfoPtr modes;
-	int count_modes;
-	int i;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	chamelium_unplug(chamelium, port);
-	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
-
-	igt_flush_uevents(mon);
-	chamelium_plug(chamelium, port);
-	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
-	igt_flush_uevents(mon);
-
-	connector = chamelium_port_get_connector(chamelium, port, true);
-	modes = connector->modes;
-	count_modes = connector->count_modes;
-
-	output = get_output_for_port(data, port);
-	pipe = get_pipe_for_output(&data->display, output);
-	igt_output_set_pipe(output, pipe);
-
-	for (i = 0; i < count_modes; ++i)
-		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
-
-	for (i = 0; i < count_modes; ++i) {
-		struct igt_fb fb = { 0 };
-		bool is_video_stable;
-		int screen_res_w, screen_res_h;
-
-		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
-			 modes[i].vrefresh);
-
-		/* Set the screen mode with the one we chose. */
-		create_fb_for_mode(data, &fb, &modes[i]);
-		enable_output(data, port, output, &modes[i], &fb);
-		is_video_stable = chamelium_port_wait_video_input_stable(
-			chamelium, port, 10);
-		igt_assert(is_video_stable);
-
-		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
-					      &screen_res_h);
-		igt_assert_eq(screen_res_w, modes[i].hdisplay);
-		igt_assert_eq(screen_res_h, modes[i].vdisplay);
-
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	igt_modeset_disable_all_outputs(&data->display);
-	drmModeFreeConnector(connector);
-}
-
-#define for_each_port(p, port)            \
-	for (p = 0, port = data.ports[p]; \
-	     p < data.port_count;         \
-	     p++, port = data.ports[p])
-
-#define connector_subtest(name__, type__)                    \
-	igt_subtest(name__)                                  \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-#define connector_dynamic_subtest(name__, type__)            \
-	igt_subtest_with_dynamic(name__)                     \
-		for_each_port(p, port)                       \
-			if (chamelium_port_get_type(port) == \
-			    DRM_MODE_CONNECTOR_ ## type__)
-
-
-static data_t data;
-
-IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
-igt_main
-{
-	struct chamelium_port *port;
-	int p;
-	size_t i;
-
-	igt_fixture {
-		/* So fbcon doesn't try to reprobe things itself */
-		kmstest_set_vt_graphics_mode();
-
-		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
-
-		/*
-		 * XXX: disabling modeset, can be removed when
-		 * igt_display_require will start doing this for us
-		 */
-		igt_display_commit2(&data.display, COMMIT_ATOMIC);
-
-		/* we need to initalize chamelium after igt_display_require */
-		data.chamelium = chamelium_init(data.drm_fd, &data.display);
-		igt_require(data.chamelium);
-
-		data.ports = chamelium_get_ports(data.chamelium,
-						 &data.port_count);
-
-		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
-			data.edids[i] = chamelium_new_edid(data.chamelium,
-							   igt_kms_get_custom_edid(i));
-		}
-	}
-
-	igt_describe("DisplayPort tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-fast", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("dp-edid-read", DisplayPort) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_4K,
-					       ARRAY_SIZE(DP_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("dp-edid-stress-resolution-non-4k",
-				  DisplayPort)
-			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
-					       ARRAY_SIZE(DP_EDIDS_NON_4K));
-
-		igt_describe(igt_edid_resolution_list_desc);
-		connector_subtest("dp-edid-resolution-list", DisplayPort)
-			edid_resolution_list(&data, port);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-suspend", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("dp-hpd-storm", DisplayPort)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("dp-hpd-storm-disable", DisplayPort)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_DP);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("dp-crc-fast", DisplayPort)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("dp-frame-dump", DisplayPort)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("dp-mode-timings", DisplayPort)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("dp-audio", DisplayPort)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("dp-audio-edid", DisplayPort)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_DP_AUDIO);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("HDMI tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_DP_HDMI,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-fast", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("hdmi-edid-read", HDMIA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_4K));
-
-		igt_describe(igt_edid_stress_resolution_desc);
-		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
-			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
-					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_storm_detect_desc);
-		connector_subtest("hdmi-hpd-storm", HDMIA)
-			test_hpd_storm_detect(&data, port,
-					      HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_hpd_storm_disable_desc);
-		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
-			test_hpd_storm_disable(&data, port,
-					       HPD_STORM_PULSE_INTERVAL_HDMI);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_MEM,
-							SUSPEND_TEST_NONE,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_suspend_resume_edid_change_desc);
-		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
-			test_suspend_resume_edid_change(&data, port,
-							SUSPEND_STATE_DISK,
-							SUSPEND_TEST_DEVICES,
-							IGT_CUSTOM_EDID_BASE,
-							IGT_CUSTOM_EDID_ALT);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_subtest("hdmi-crc-fast", HDMIA)
-			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
-					      CHAMELIUM_CHECK_CRC, 1);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_CRC, 3);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CRC, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-crc-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CRC);
-
-		igt_describe(test_display_one_mode_desc);
-		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
-			int k;
-			igt_output_t *output;
-			igt_plane_t *primary;
-
-			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
-			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-			igt_assert(primary);
-
-			for (k = 0; k < primary->format_mod_count; k++) {
-				if (!igt_fb_supported_format(primary->formats[k]))
-					continue;
-
-				if (!igt_format_is_yuv(primary->formats[k]))
-					continue;
-
-				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
-					continue;
-
-				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
-					test_display_one_mode(&data, port, primary->formats[k],
-							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
-			}
-		}
-
-		igt_describe(test_display_planes_random_desc);
-		connector_subtest("hdmi-cmp-planes-random", HDMIA)
-			test_display_planes_random(&data, port,
-						   CHAMELIUM_CHECK_CHECKERBOARD);
-
-		igt_describe(test_display_frame_dump_desc);
-		connector_subtest("hdmi-frame-dump", HDMIA)
-			test_display_frame_dump(&data, port);
-
-		igt_describe(test_mode_timings_desc);
-		connector_subtest("hdmi-mode-timings", HDMIA)
-			test_mode_timings(&data, port);
-
-		igt_describe(test_display_audio_desc);
-		connector_subtest("hdmi-audio", HDMIA)
-			test_display_audio(&data, port, "HDMI",
-					   IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_audio_edid_desc);
-		connector_subtest("hdmi-audio-edid", HDMIA)
-			test_display_audio_edid(&data, port,
-						IGT_CUSTOM_EDID_HDMI_AUDIO);
-
-		igt_describe(test_display_aspect_ratio_desc);
-		connector_subtest("hdmi-aspect-ratio", HDMIA)
-			test_display_aspect_ratio(&data, port);
-
-		igt_describe(test_hotplug_for_each_pipe_desc);
-		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
-			test_hotplug_for_each_pipe(&data, port);
-	}
-
-	igt_describe("VGA tests");
-	igt_subtest_group {
-		igt_fixture {
-			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
-							    data.port_count, 1);
-		}
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-fast", VGA)
-			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-enable-disable-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON_OFF);
-
-		igt_describe(test_basic_hotplug_desc);
-		connector_subtest("vga-hpd-with-enabled-mode", VGA)
-			test_hotplug(&data, port,
-				     HPD_TOGGLE_COUNT_FAST,
-				     TEST_MODESET_ON);
-
-		igt_describe(igt_custom_edid_type_read_desc);
-		connector_subtest("vga-edid-read", VGA) {
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
-			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
-		}
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-suspend", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_MEM,
-						SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_desc);
-		connector_subtest("vga-hpd-after-hibernate", VGA)
-			test_suspend_resume_hpd(&data, port,
-						SUSPEND_STATE_DISK,
-						SUSPEND_TEST_DEVICES);
-
-		igt_describe(test_hpd_without_ddc_desc);
-		connector_subtest("vga-hpd-without-ddc", VGA)
-			test_hpd_without_ddc(&data, port);
-
-		igt_describe(test_display_all_modes_desc);
-		connector_subtest("vga-frame-dump", VGA)
-			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
-					       CHAMELIUM_CHECK_ANALOG, 1);
-	}
-
-	igt_describe("Tests that operate on all connectors");
-	igt_subtest_group {
-
-		igt_fixture {
-			igt_require(data.port_count);
-		}
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-suspend")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_MEM,
-						       SUSPEND_TEST_NONE);
-
-		igt_describe(test_suspend_resume_hpd_common_desc);
-		igt_subtest("common-hpd-after-hibernate")
-			test_suspend_resume_hpd_common(&data,
-						       SUSPEND_STATE_DISK,
-						       SUSPEND_TEST_DEVICES);
-	}
-
-	igt_describe(test_hotplug_for_each_pipe_desc);
-	connector_subtest("vga-hpd-for-each-pipe", VGA)
-		test_hotplug_for_each_pipe(&data, port);
-
-	igt_fixture {
-		igt_display_fini(&data.display);
-		close(data.drm_fd);
-	}
-}
diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
new file mode 100644
index 00000000..4d13744c
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_audio.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the Audio functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+/* Playback parameters control the audio signal we synthesize and send */
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_SAMPLES 1024
+
+/* Capture paremeters control the audio signal we receive */
+#define CAPTURE_SAMPLES 2048
+
+#define AUDIO_TIMEOUT 2000 /* ms */
+/* A streak of 3 gives confidence that the signal is good. */
+#define MIN_STREAK 3
+
+#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
+#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
+#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
+
+struct audio_state {
+	struct alsa *alsa;
+	struct chamelium *chamelium;
+	struct chamelium_port *port;
+	struct chamelium_stream *stream;
+
+	/* The capture format is only available after capture has started. */
+	struct {
+		snd_pcm_format_t format;
+		int channels;
+		int rate;
+	} playback, capture;
+
+	char *name;
+	struct audio_signal *signal; /* for frequencies test only */
+	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	size_t recv_pages;
+	int msec;
+
+	int dump_fd;
+	char *dump_path;
+
+	pthread_t thread;
+	atomic_bool run;
+	atomic_bool positive; /* for pulse test only */
+};
+
+/* TODO: enable >48KHz rates, these are not reliable */
+static int test_sampling_rates[] = {
+	32000, 44100, 48000,
+	/* 88200, */
+	/* 96000, */
+	/* 176400, */
+	/* 192000, */
+};
+
+static int test_sampling_rates_count =
+	sizeof(test_sampling_rates) / sizeof(int);
+
+/* Test frequencies (Hz): a sine signal will be generated for each.
+ *
+ * Depending on the sampling rate chosen, it might not be possible to properly
+ * detect the generated sine (see Nyquist–Shannon sampling theorem).
+ * Frequencies that can't be reliably detected will be automatically pruned in
+ * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
+ * tested with a 192KHz sampling rate.
+ */
+static int test_frequencies[] = {
+	300, 600, 1200, 10000, 80000,
+};
+
+static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
+
+static const snd_pcm_format_t test_formats[] = {
+	SND_PCM_FORMAT_S16_LE,
+	SND_PCM_FORMAT_S24_LE,
+	SND_PCM_FORMAT_S32_LE,
+};
+
+static const size_t test_formats_count =
+	sizeof(test_formats) / sizeof(test_formats[0]);
+
+static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
+			     struct alsa *alsa, struct chamelium_port *port,
+			     snd_pcm_format_t format, int channels, int rate)
+{
+	memset(state, 0, sizeof(*state));
+	state->dump_fd = -1;
+
+	state->alsa = alsa;
+	state->chamelium = data->chamelium;
+	state->port = port;
+
+	state->playback.format = format;
+	state->playback.channels = channels;
+	state->playback.rate = rate;
+
+	alsa_configure_output(alsa, format, channels, rate);
+
+	state->stream = chamelium_stream_init();
+	igt_assert_f(state->stream,
+		     "Failed to initialize Chamelium stream client\n");
+}
+
+static void audio_state_fini(struct audio_state *state)
+{
+	chamelium_stream_deinit(state->stream);
+	free(state->name);
+}
+
+static void *run_audio_thread(void *data)
+{
+	struct alsa *alsa = data;
+
+	alsa_run(alsa, -1);
+	return NULL;
+}
+
+static void audio_state_start(struct audio_state *state, const char *name)
+{
+	int ret;
+	bool ok;
+	size_t i, j;
+	enum chamelium_stream_realtime_mode stream_mode;
+	char dump_suffix[64];
+
+	free(state->name);
+	state->name = strdup(name);
+	state->recv_pages = 0;
+	state->msec = 0;
+
+	igt_debug("Starting %s test with playback format %s, "
+		  "sampling rate %d Hz and %d channels\n",
+		  name, snd_pcm_format_name(state->playback.format),
+		  state->playback.rate, state->playback.channels);
+
+	chamelium_start_capturing_audio(state->chamelium, state->port, false);
+
+	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
+	igt_assert_f(ok, "Failed to start streaming audio capture\n");
+
+	/* Start playing audio */
+	state->run = true;
+	ret = pthread_create(&state->thread, NULL, run_audio_thread,
+			     state->alsa);
+	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
+
+	/* The Chamelium device only supports this PCM format. */
+	state->capture.format = SND_PCM_FORMAT_S32_LE;
+
+	/* Only after we've started playing audio, we can retrieve the capture
+	 * format used by the Chamelium device. */
+	chamelium_get_audio_format(state->chamelium, state->port,
+				   &state->capture.rate,
+				   &state->capture.channels);
+	if (state->capture.rate == 0) {
+		igt_debug("Audio receiver doesn't indicate the capture "
+			  "sampling rate, assuming it's %d Hz\n",
+			  state->playback.rate);
+		state->capture.rate = state->playback.rate;
+	}
+
+	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
+					    state->channel_mapping);
+	/* Make sure we can capture all channels we send. */
+	for (i = 0; i < state->playback.channels; i++) {
+		ok = false;
+		for (j = 0; j < state->capture.channels; j++) {
+			if (state->channel_mapping[j] == i) {
+				ok = true;
+				break;
+			}
+		}
+		igt_assert_f(ok, "Cannot capture all channels\n");
+	}
+
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix),
+			 "capture-%s-%s-%dch-%dHz", name,
+			 snd_pcm_format_name(state->playback.format),
+			 state->playback.channels, state->playback.rate);
+
+		state->dump_fd = audio_create_wav_file_s32_le(
+			dump_suffix, state->capture.rate,
+			state->capture.channels, &state->dump_path);
+		igt_assert_f(state->dump_fd >= 0,
+			     "Failed to create audio dump file\n");
+	}
+}
+
+static void audio_state_receive(struct audio_state *state, int32_t **recv,
+				size_t *recv_len)
+{
+	bool ok;
+	size_t page_count;
+	size_t recv_size;
+
+	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
+						     recv, recv_len);
+	igt_assert_f(ok, "Failed to receive audio from stream server\n");
+
+	state->msec = state->recv_pages * *recv_len /
+		      (double)state->capture.channels /
+		      (double)state->capture.rate * 1000;
+	state->recv_pages++;
+
+	if (state->dump_fd >= 0) {
+		recv_size = *recv_len * sizeof(int32_t);
+		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
+				     recv_size,
+			     "Failed to write to audio dump file\n");
+	}
+}
+
+static void audio_state_stop(struct audio_state *state, bool success)
+{
+	bool ok;
+	int ret;
+	struct chamelium_audio_file *audio_file;
+	enum igt_log_level log_level;
+
+	igt_debug("Stopping audio playback\n");
+	state->run = false;
+	ret = pthread_join(state->thread, NULL);
+	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
+
+	ok = chamelium_stream_stop_realtime_audio(state->stream);
+	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
+
+	audio_file =
+		chamelium_stop_capturing_audio(state->chamelium, state->port);
+	if (audio_file) {
+		igt_debug("Audio file saved on the Chamelium in %s\n",
+			  audio_file->path);
+		chamelium_destroy_audio_file(audio_file);
+	}
+
+	if (state->dump_fd >= 0) {
+		close(state->dump_fd);
+		state->dump_fd = -1;
+
+		if (success) {
+			/* Test succeeded, no need to keep the captured data */
+			unlink(state->dump_path);
+		} else
+			igt_debug("Saved captured audio data to %s\n",
+				  state->dump_path);
+		free(state->dump_path);
+		state->dump_path = NULL;
+	}
+
+	if (success)
+		log_level = IGT_LOG_DEBUG;
+	else
+		log_level = IGT_LOG_CRITICAL;
+
+	igt_log(IGT_LOG_DOMAIN, log_level,
+		"Audio %s test result for format %s, "
+		"sampling rate %d Hz and %d channels: %s\n",
+		state->name, snd_pcm_format_name(state->playback.format),
+		state->playback.rate, state->playback.channels,
+		success ? "ALL GREEN" : "FAILED");
+}
+
+static void check_audio_infoframe(struct audio_state *state)
+{
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_audio infoframe_audio;
+	struct infoframe_audio expected = { 0 };
+	bool ok;
+
+	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
+		igt_debug("Skipping audio InfoFrame check: "
+			  "Chamelium board doesn't support GetLastInfoFrame\n");
+		return;
+	}
+
+	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
+	expected.channel_count = state->playback.channels;
+	expected.sampling_freq = state->playback.rate;
+	expected.sample_size = snd_pcm_format_width(state->playback.format);
+
+	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
+						 CHAMELIUM_INFOFRAME_AUDIO);
+	if (infoframe == NULL && state->playback.channels <= 2) {
+		/* Audio InfoFrames are optional for mono and stereo audio */
+		igt_debug("Skipping audio InfoFrame check: "
+			  "no InfoFrame received\n");
+		return;
+	}
+	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
+
+	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
+				   infoframe->payload, infoframe->payload_size);
+	chamelium_infoframe_destroy(infoframe);
+	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
+
+	igt_debug("Checking audio InfoFrame:\n");
+	igt_debug("coding_type: got %d, expected %d\n",
+		  infoframe_audio.coding_type, expected.coding_type);
+	igt_debug("channel_count: got %d, expected %d\n",
+		  infoframe_audio.channel_count, expected.channel_count);
+	igt_debug("sampling_freq: got %d, expected %d\n",
+		  infoframe_audio.sampling_freq, expected.sampling_freq);
+	igt_debug("sample_size: got %d, expected %d\n",
+		  infoframe_audio.sample_size, expected.sample_size);
+
+	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
+		igt_assert(infoframe_audio.coding_type == expected.coding_type);
+	if (infoframe_audio.channel_count >= 0)
+		igt_assert(infoframe_audio.channel_count ==
+			   expected.channel_count);
+	if (infoframe_audio.sampling_freq >= 0)
+		igt_assert(infoframe_audio.sampling_freq ==
+			   expected.sampling_freq);
+	if (infoframe_audio.sample_size >= 0)
+		igt_assert(infoframe_audio.sample_size == expected.sample_size);
+}
+
+static int audio_output_frequencies_callback(void *data, void *buffer,
+					     int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	audio_signal_fill(state->signal, tmp, samples);
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool test_audio_frequencies(struct audio_state *state)
+{
+	int freq, step;
+	int32_t *recv, *buf;
+	double *channel;
+	size_t i, j, streak;
+	size_t recv_len, buf_len, buf_cap, channel_len;
+	bool success;
+	int capture_chan;
+
+	state->signal = audio_signal_init(state->playback.channels,
+					  state->playback.rate);
+	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
+
+	/* We'll choose different frequencies per channel to make sure they are
+	 * independent from each other. To do so, we'll add a different offset
+	 * to the base frequencies for each channel. We need to choose a big
+	 * enough offset so that we're sure to detect mixed up channels. We
+	 * choose an offset of two 2 bins in the final FFT to enforce a clear
+	 * difference.
+	 *
+	 * Note that we assume capture_rate == playback_rate. We'll assert this
+	 * later on. We cannot retrieve the capture rate before starting
+	 * playing audio, so we don't really have the choice.
+	 */
+	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
+	for (i = 0; i < test_frequencies_count; i++) {
+		for (j = 0; j < state->playback.channels; j++) {
+			freq = test_frequencies[i] + j * step;
+			audio_signal_add_frequency(state->signal, freq, j);
+		}
+	}
+	audio_signal_synthesize(state->signal);
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_frequencies_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	audio_state_start(state, "frequencies");
+
+	igt_assert_f(state->capture.rate == state->playback.rate,
+		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
+		     state->capture.rate, state->playback.rate);
+
+	/* Needs to be a multiple of 128, because that's the number of samples
+	 * we get per channel each time we receive an audio page from the
+	 * Chamelium device.
+	 *
+	 * Additionally, this value needs to be high enough to guarantee we
+	 * capture a full period of each sine we generate. If we capture 2048
+	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
+	 * sines. For lower sampling rates, the capture duration will be
+	 * longer.
+	 */
+	channel_len = CAPTURE_SAMPLES;
+	channel = malloc(sizeof(double) * channel_len);
+
+	buf_cap = state->capture.channels * channel_len;
+	buf = malloc(sizeof(int32_t) * buf_cap);
+	buf_len = 0;
+
+	recv = NULL;
+	recv_len = 0;
+
+	success = false;
+	streak = 0;
+	while (!success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
+		buf_len += recv_len;
+
+		if (buf_len < buf_cap)
+			continue;
+		igt_assert(buf_len == buf_cap);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (j = 0; j < state->playback.channels; j++) {
+			capture_chan = state->channel_mapping[j];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  j, capture_chan);
+
+			audio_extract_channel_s32_le(channel, channel_len, buf,
+						     buf_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			if (audio_signal_detect(state->signal,
+						state->capture.rate, j, channel,
+						channel_len))
+				streak++;
+			else
+				streak = 0;
+		}
+
+		buf_len = 0;
+
+		success = streak == MIN_STREAK * state->playback.channels;
+	}
+
+	audio_state_stop(state, success);
+
+	free(recv);
+	free(buf);
+	free(channel);
+	audio_signal_fini(state->signal);
+
+	check_audio_infoframe(state);
+
+	return success;
+}
+
+static int audio_output_flatline_callback(void *data, void *buffer, int samples)
+{
+	struct audio_state *state = data;
+	double *tmp;
+	size_t len, i;
+
+	len = samples * state->playback.channels;
+	tmp = malloc(len * sizeof(double));
+	for (i = 0; i < len; i++)
+		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
+	audio_convert_to(buffer, tmp, len, state->playback.format);
+	free(tmp);
+
+	return state->run ? 0 : -1;
+}
+
+static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
+{
+	double expected, min, max;
+	size_t i;
+	bool ok;
+
+	min = max = NAN;
+	for (i = 0; i < buf_len; i++) {
+		if (isnan(min) || buf[i] < min)
+			min = buf[i];
+		if (isnan(max) || buf[i] > max)
+			max = buf[i];
+	}
+
+	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
+	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
+	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
+	if (ok)
+		igt_debug("Flatline wave amplitude detected\n");
+	else
+		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
+			  min, max);
+	return ok;
+}
+
+static ssize_t detect_falling_edge(double *buf, size_t buf_len)
+{
+	size_t i;
+
+	for (i = 0; i < buf_len; i++) {
+		if (buf[i] < 0)
+			return i;
+	}
+
+	return -1;
+}
+
+/** test_audio_flatline:
+ *
+ * Send a constant value (one positive, then a negative one) and check that:
+ *
+ * - The amplitude of the flatline is correct
+ * - All channels switch from a positive signal to a negative one at the same
+ *   time (ie. all channels are aligned)
+ */
+static bool test_audio_flatline(struct audio_state *state)
+{
+	bool success, amp_success, align_success;
+	int32_t *recv;
+	size_t recv_len, i, channel_len;
+	ssize_t j;
+	int streak, capture_chan;
+	double *channel;
+	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
+
+	alsa_register_output_callback(state->alsa,
+				      audio_output_flatline_callback, state,
+				      PLAYBACK_SAMPLES);
+
+	/* Start by sending a positive signal */
+	state->positive = true;
+
+	audio_state_start(state, "flatline");
+
+	for (i = 0; i < state->playback.channels; i++)
+		falling_edges[i] = -1;
+
+	recv = NULL;
+	recv_len = 0;
+	amp_success = false;
+	streak = 0;
+	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
+		audio_state_receive(state, &recv, &recv_len);
+
+		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+		for (i = 0; i < state->playback.channels; i++) {
+			capture_chan = state->channel_mapping[i];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n",
+				  i, capture_chan);
+
+			channel_len = audio_extract_channel_s32_le(
+				NULL, 0, recv, recv_len,
+				state->capture.channels, capture_chan);
+			channel = malloc(channel_len * sizeof(double));
+			audio_extract_channel_s32_le(channel, channel_len, recv,
+						     recv_len,
+						     state->capture.channels,
+						     capture_chan);
+
+			/* Check whether the amplitude is fine */
+			if (detect_flatline_amplitude(channel, channel_len,
+						      state->positive))
+				streak++;
+			else
+				streak = 0;
+
+			/* If we're now sending a negative signal, detect the
+			 * falling edge */
+			j = detect_falling_edge(channel, channel_len);
+			if (!state->positive && j >= 0) {
+				falling_edges[i] =
+					recv_len * state->recv_pages + j;
+			}
+
+			free(channel);
+		}
+
+		amp_success = streak == MIN_STREAK * state->playback.channels;
+
+		if (amp_success && state->positive) {
+			/* Switch to a negative signal after we've detected the
+			 * positive one. */
+			state->positive = false;
+			amp_success = false;
+			streak = 0;
+			igt_debug("Switching to negative square wave\n");
+		}
+	}
+
+	/* Check alignment between all channels by comparing the index of the
+	 * falling edge. */
+	align_success = true;
+	for (i = 0; i < state->playback.channels; i++) {
+		if (falling_edges[i] < 0) {
+			igt_critical(
+				"Falling edge not detected for channel %zu\n",
+				i);
+			align_success = false;
+			continue;
+		}
+
+		if (abs(falling_edges[0] - falling_edges[i]) >
+		    FLATLINE_ALIGN_ACCURACY) {
+			igt_critical("Channel alignment mismatch: "
+				     "channel 0 has a falling edge at index %d "
+				     "while channel %zu has index %d\n",
+				     falling_edges[0], i, falling_edges[i]);
+			align_success = false;
+		}
+	}
+
+	success = amp_success && align_success;
+	audio_state_stop(state, success);
+
+	free(recv);
+
+	return success;
+}
+
+static bool check_audio_configuration(struct alsa *alsa,
+				      snd_pcm_format_t format, int channels,
+				      int sampling_rate)
+{
+	if (!alsa_test_output_configuration(alsa, format, channels,
+					    sampling_rate)) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because at least one of the "
+			  "selected output devices doesn't support this "
+			  "configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	/* TODO: the Chamelium device sends a malformed signal for some audio
+	 * configurations. See crbug.com/950917 */
+	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
+	    channels > 2) {
+		igt_debug("Skipping test with format %s, sampling rate %d Hz "
+			  "and %d channels because the Chamelium device "
+			  "doesn't support this configuration\n",
+			  snd_pcm_format_name(format), sampling_rate, channels);
+		return false;
+	}
+	return true;
+}
+
+static const char test_display_audio_desc[] =
+	"Playback various audio signals with various audio formats/rates, "
+	"capture them and check they are correct";
+static void test_display_audio(chamelium_data_t *data,
+			       struct chamelium_port *port,
+			       const char *audio_device,
+			       enum igt_custom_edid_type edid)
+{
+	bool run, success;
+	struct alsa *alsa;
+	int ret;
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id, i, j;
+	int channels, sampling_rate;
+	snd_pcm_format_t format;
+	struct audio_state state;
+
+	igt_require(alsa_has_exclusive_access());
+
+	/* Old Chamelium devices need an update for DisplayPort audio and
+	 * chamelium_get_audio_format support. */
+	igt_require(chamelium_has_audio_support(data->chamelium, port));
+
+	alsa = alsa_init();
+	igt_assert(alsa);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because the receiver won't try to receive audio if
+	 * it doesn't receive video. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	run = false;
+	success = true;
+	for (i = 0; i < test_sampling_rates_count; i++) {
+		for (j = 0; j < test_formats_count; j++) {
+			ret = alsa_open_output(alsa, audio_device);
+			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
+
+			/* TODO: playback on all 8 available channels (this
+			 * isn't supported by Chamelium devices yet, see
+			 * https://crbug.com/950917) */
+			format = test_formats[j];
+			channels = PLAYBACK_CHANNELS;
+			sampling_rate = test_sampling_rates[i];
+
+			if (!check_audio_configuration(alsa, format, channels,
+						       sampling_rate))
+				continue;
+
+			run = true;
+
+			audio_state_init(&state, data, alsa, port, format,
+					 channels, sampling_rate);
+			success &= test_audio_frequencies(&state);
+			success &= test_audio_flatline(&state);
+			audio_state_fini(&state);
+
+			alsa_close_output(alsa);
+		}
+	}
+
+	/* Make sure we tested at least one frequency and format. */
+	igt_assert(run);
+	/* Make sure all runs were successful. */
+	igt_assert(success);
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+
+	free(alsa);
+}
+
+static const char test_display_audio_edid_desc[] =
+	"Plug a connector with an EDID suitable for audio, check ALSA's "
+	"EDID-Like Data reports the correct audio parameters";
+static void test_display_audio_edid(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_custom_edid_type edid)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id;
+	struct eld_entry eld;
+	struct eld_sad *sad;
+
+	igt_require(eld_is_supported());
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, edid);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because audio cannot be played on inactive
+	 * connectors. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	igt_assert(eld_get_igt(&eld));
+	igt_assert(eld.sads_len == 1);
+
+	sad = &eld.sads[0];
+	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
+	igt_assert(sad->channels == 2);
+	igt_assert(sad->rates ==
+		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
+		    CEA_SAD_SAMPLING_RATE_48KHZ));
+	igt_assert(sad->bits ==
+		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
+		    CEA_SAD_SAMPLE_SIZE_24));
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+}
+
+IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("dp-audio", DisplayPort) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("dp-audio-edid", DisplayPort)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_DP_AUDIO);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_audio_desc);
+		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
+			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
+
+		igt_describe(test_display_audio_edid_desc);
+		connector_subtest("hdmi-audio-edid", HDMIA)
+			test_display_audio_edid(&data, port,
+						IGT_CUSTOM_EDID_HDMI_AUDIO);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
similarity index 100%
rename from tests/chamelium/kms_color_chamelium.c
rename to tests/chamelium/kms_chamelium_color.c
diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
new file mode 100644
index 00000000..d6b6045e
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_edid.c
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the EDID functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include <stdint.h>
+#include <xf86drmMode.h>
+
+#include "igt_chamelium.h"
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+#include "monitor_edids/dp_edids.h"
+#include "monitor_edids/hdmi_edids.h"
+#include "monitor_edids/monitor_edids_helper.h"
+
+#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
+
+static void get_connectors_link_status_failed(chamelium_data_t *data,
+					      bool *link_status_failed)
+{
+	drmModeConnector *connector;
+	uint64_t link_status;
+	drmModePropertyPtr prop;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		connector = chamelium_port_get_connector(data->chamelium,
+							 data->ports[p], false);
+
+		igt_assert(kmstest_get_property(
+			data->drm_fd, connector->connector_id,
+			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
+			&link_status, &prop));
+
+		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
+
+		drmModeFreeProperty(prop);
+		drmModeFreeConnector(connector);
+	}
+}
+
+static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
+		       drmModeModeInfo *mode)
+{
+	struct chamelium_video_params video_params = { 0 };
+	double mode_clock;
+	int mode_hsync_offset, mode_vsync_offset;
+	int mode_hsync_width, mode_vsync_width;
+	int mode_hsync_polarity, mode_vsync_polarity;
+
+	chamelium_port_get_video_params(chamelium, port, &video_params);
+
+	mode_clock = (double)mode->clock / 1000;
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
+		/* this is what chamelium understands as offsets for DP */
+		mode_hsync_offset = mode->htotal - mode->hsync_start;
+		mode_vsync_offset = mode->vtotal - mode->vsync_start;
+	} else {
+		/* and this is what they are for other connectors */
+		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
+		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
+	}
+
+	mode_hsync_width = mode->hsync_end - mode->hsync_start;
+	mode_vsync_width = mode->vsync_end - mode->vsync_start;
+
+	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	igt_debug("Checking video mode:\n");
+	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
+		  mode_clock, MODE_CLOCK_ACCURACY * 100);
+	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
+		  mode->hdisplay);
+	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
+		  mode->vdisplay);
+	igt_debug("hsync_offset: got %d, expected %d\n",
+		  video_params.hsync_offset, mode_hsync_offset);
+	igt_debug("vsync_offset: got %d, expected %d\n",
+		  video_params.vsync_offset, mode_vsync_offset);
+	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
+		  mode->htotal);
+	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
+		  mode->vtotal);
+	igt_debug("hsync_width: got %d, expected %d\n",
+		  video_params.hsync_width, mode_hsync_width);
+	igt_debug("vsync_width: got %d, expected %d\n",
+		  video_params.vsync_width, mode_vsync_width);
+	igt_debug("hsync_polarity: got %d, expected %d\n",
+		  video_params.hsync_polarity, mode_hsync_polarity);
+	igt_debug("vsync_polarity: got %d, expected %d\n",
+		  video_params.vsync_polarity, mode_vsync_polarity);
+
+	if (!isnan(video_params.clock)) {
+		igt_assert(video_params.clock >
+			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
+		igt_assert(video_params.clock <
+			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
+	}
+	igt_assert(video_params.hactive == mode->hdisplay);
+	igt_assert(video_params.vactive == mode->vdisplay);
+	igt_assert(video_params.hsync_offset == mode_hsync_offset);
+	igt_assert(video_params.vsync_offset == mode_vsync_offset);
+	igt_assert(video_params.htotal == mode->htotal);
+	igt_assert(video_params.vtotal == mode->vtotal);
+	igt_assert(video_params.hsync_width == mode_hsync_width);
+	igt_assert(video_params.vsync_width == mode_vsync_width);
+	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
+	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
+}
+
+static const char igt_custom_edid_type_read_desc[] =
+	"Make sure the EDID exposed by KMS is the same as the screen's";
+static void igt_custom_edid_type_read(chamelium_data_t *data,
+				      struct chamelium_port *port,
+				      enum igt_custom_edid_type edid)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector;
+	size_t raw_edid_size;
+	const struct edid *raw_edid;
+	uint64_t edid_blob_id;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_skip_on(chamelium_check_analog_bridge(data, port));
+
+	connector = chamelium_port_get_connector(data->chamelium, port, true);
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob_id != 0);
+	edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
+	igt_assert(edid_blob);
+
+	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
+	raw_edid_size = edid_get_size(raw_edid);
+	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+}
+
+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(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   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;
+
+		monitor_edid *edid = &edids_list[i];
+		igt_info("Testing out the EDID for %s\n",
+			 monitor_edid_get_name(edid));
+
+		/* Getting and Setting the EDID on Chamelium. */
+		chamelium_edid =
+			get_chameleon_edid_from_monitor_edid(chamelium, 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);
+		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
+		chamelium_create_fb_for_mode(data, &fb, &mode);
+		output = chamelium_get_output_for_port(data, port);
+		pipe = chamelium_get_pipe_for_output(&data->display, output);
+		igt_output_set_pipe(output, pipe);
+		chamelium_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);
+}
+
+static const char igt_edid_resolution_list_desc[] =
+	"Get an EDID with many modes of different configurations, set them on the screen and check the"
+	" screen resolution matches the mode resolution.";
+
+static void edid_resolution_list(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct chamelium *chamelium = data->chamelium;
+	struct udev_monitor *mon = igt_watch_uevents();
+	drmModeConnector *connector;
+	drmModeModeInfoPtr modes;
+	int count_modes;
+	int i;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	chamelium_unplug(chamelium, port);
+	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
+
+	igt_flush_uevents(mon);
+	chamelium_plug(chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_CONNECTED);
+	igt_flush_uevents(mon);
+
+	connector = chamelium_port_get_connector(chamelium, port, true);
+	modes = connector->modes;
+	count_modes = connector->count_modes;
+
+	output = chamelium_get_output_for_port(data, port);
+	pipe = chamelium_get_pipe_for_output(&data->display, output);
+	igt_output_set_pipe(output, pipe);
+
+	for (i = 0; i < count_modes; ++i)
+		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
+
+	for (i = 0; i < count_modes; ++i) {
+		struct igt_fb fb = { 0 };
+		bool is_video_stable;
+		int screen_res_w, screen_res_h;
+
+		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
+			 modes[i].vrefresh);
+
+		/* Set the screen mode with the one we chose. */
+		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
+		chamelium_enable_output(data, port, output, &modes[i], &fb);
+		is_video_stable = chamelium_port_wait_video_input_stable(
+			chamelium, port, 10);
+		igt_assert(is_video_stable);
+
+		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
+					      &screen_res_h);
+		igt_assert_eq(screen_res_w, modes[i].hdisplay);
+		igt_assert_eq(screen_res_h, modes[i].vdisplay);
+
+		igt_remove_fb(data->drm_fd, &fb);
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_suspend_resume_edid_change_desc[] =
+	"Simulate a screen being unplugged and another screen being plugged "
+	"during suspend, check that a uevent is sent and connector status is "
+	"updated";
+static void test_suspend_resume_edid_change(chamelium_data_t *data,
+					    struct chamelium_port *port,
+					    enum igt_suspend_state state,
+					    enum igt_suspend_test test,
+					    enum igt_custom_edid_type edid,
+					    enum igt_custom_edid_type alt_edid)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	bool link_status_failed[2][data->port_count];
+	int p;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Catch the event and flush all remaining ones. */
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_flush_uevents(mon);
+
+	/* First plug in the port */
+	chamelium_set_edid(data, port, edid);
+	chamelium_plug(data->chamelium, port);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	/*
+	 * Change the edid before we suspend. On resume, the machine should
+	 * notice the EDID change and fire a hotplug event.
+	 */
+	chamelium_set_edid(data, port, alt_edid);
+
+	get_connectors_link_status_failed(data, link_status_failed[0]);
+
+	igt_flush_uevents(mon);
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	get_connectors_link_status_failed(data, link_status_failed[1]);
+
+	for (p = 0; p < data->port_count; p++)
+		igt_skip_on(!link_status_failed[0][p] &&
+			    link_status_failed[1][p]);
+}
+
+static const char test_mode_timings_desc[] =
+	"For each mode of the IGT base EDID, perform a modeset and check the "
+	"mode detected by the Chamelium receiver matches the mode we set";
+static void test_mode_timings(chamelium_data_t *data,
+			      struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	igt_require(chamelium_supports_get_video_params(data->chamelium));
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+		int fb_id;
+		struct igt_fb fb;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		/* Trigger the FSM */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
+
+		check_mode(data->chamelium, port, mode);
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("dp-edid-read", DisplayPort)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_4K,
+					       ARRAY_SIZE(DP_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("dp-edid-stress-resolution-non-4k",
+				  DisplayPort)
+			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
+					       ARRAY_SIZE(DP_EDIDS_NON_4K));
+
+		igt_describe(igt_edid_resolution_list_desc);
+		connector_subtest("dp-edid-resolution-list", DisplayPort)
+			edid_resolution_list(&data, port);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("dp-edid-change-during-hibernate",
+				  DisplayPort)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("dp-mode-timings", DisplayPort)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("hdmi-edid-read", HDMIA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_4K));
+
+		igt_describe(igt_edid_stress_resolution_desc);
+		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
+			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
+					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_MEM,
+							SUSPEND_TEST_NONE,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_suspend_resume_edid_change_desc);
+		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
+			test_suspend_resume_edid_change(&data, port,
+							SUSPEND_STATE_DISK,
+							SUSPEND_TEST_DEVICES,
+							IGT_CUSTOM_EDID_BASE,
+							IGT_CUSTOM_EDID_ALT);
+
+		igt_describe(test_mode_timings_desc);
+		connector_subtest("hdmi-mode-timings", HDMIA)
+			test_mode_timings(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(igt_custom_edid_type_read_desc);
+		connector_subtest("vga-edid-read", VGA)
+		{
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_BASE);
+			igt_custom_edid_type_read(&data, port,
+						  IGT_CUSTOM_EDID_ALT);
+		}
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
new file mode 100644
index 00000000..008bc34b
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_frames.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Lyude Paul <lyude@redhat.com>
+ */
+
+#include "igt_eld.h"
+#include "igt_infoframe.h"
+#include "kms_chamelium_helper.h"
+
+#define connector_dynamic_subtest(name__, type__)                   \
+	igt_subtest_with_dynamic(name__)                            \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+struct vic_mode {
+	int hactive, vactive;
+	int vrefresh; /* Hz */
+	uint32_t picture_ar;
+};
+
+static int chamelium_vga_modes[][2] = {
+	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
+	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
+	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
+	{ 640, 480 },	{ -1, -1 },
+};
+
+/* Maps Video Identification Codes to a mode */
+static const struct vic_mode vic_modes[] = {
+	[16] = {
+		.hactive = 1920,
+		.vactive = 1080,
+		.vrefresh = 60,
+		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
+	},
+};
+
+/* Maps aspect ratios to their mode flag */
+static const uint32_t mode_ar_flags[] = {
+	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
+};
+
+static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
+{
+	int i = 0;
+
+	while (chamelium_vga_modes[i][0] != -1) {
+		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
+		    mode->vdisplay == chamelium_vga_modes[i][1])
+			return false;
+
+		i++;
+	}
+
+	return true;
+}
+
+static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
+			    igt_output_t *output, drmModeModeInfo *mode,
+			    uint32_t fourcc, enum chamelium_check check,
+			    int count)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+	struct igt_fb frame_fb, fb;
+	int i, fb_id, captured_frame_count;
+	int frame_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &fb);
+	igt_assert(fb_id > 0);
+
+	frame_id =
+		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
+	igt_assert(frame_id > 0);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
+
+	chamelium_enable_output(data, port, output, mode, &frame_fb);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		igt_crc_t *expected_crc;
+		igt_crc_t *crc;
+
+		/* We want to keep the display running for a little bit, since
+		 * there's always the potential the driver isn't able to keep
+		 * the display running properly for very long
+		 */
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == count);
+
+		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		for (i = 0; i < captured_frame_count; i++)
+			chamelium_assert_crc_eq_or_dump(
+				data->chamelium, expected_crc, &crc[i], &fb, i);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_ANALOG ||
+		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		igt_assert(count == 1);
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+
+		if (check == CHAMELIUM_CHECK_ANALOG)
+			chamelium_crop_analog_frame(dump, mode->hdisplay,
+						    mode->vdisplay);
+
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	igt_remove_fb(data->drm_fd, &frame_fb);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static enum infoframe_avi_picture_aspect_ratio
+get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
+{
+	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
+	switch (aspect_ratio) {
+	case DRM_MODE_PICTURE_ASPECT_4_3:
+		return INFOFRAME_AVI_PIC_AR_4_3;
+	case DRM_MODE_PICTURE_ASPECT_16_9:
+		return INFOFRAME_AVI_PIC_AR_16_9;
+	default:
+		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
+	}
+}
+
+static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
+				 drmModeModeInfo *drm_mode)
+{
+	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
+
+	return vic_mode->hactive == drm_mode->hdisplay &&
+	       vic_mode->vactive == drm_mode->vdisplay &&
+	       vic_mode->vrefresh == drm_mode->vrefresh &&
+	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
+}
+
+static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
+				   uint32_t height, uint32_t format,
+				   uint64_t modifier, size_t *stride)
+{
+	size_t stride_min;
+	uint32_t max_tile_w = 4, tile_w, tile_h;
+	int i;
+	struct igt_fb dummy;
+
+	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
+
+	/* Randomize the stride to less than twice the minimum. */
+	*stride = (rand() % stride_min) + stride_min;
+
+	/*
+	 * Create a dummy FB to determine bpp for each plane, and calculate
+	 * the maximum tile width from that.
+	 */
+	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
+	for (i = 0; i < dummy.num_planes; i++) {
+		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
+				     &tile_w, &tile_h);
+
+		if (tile_w > max_tile_w)
+			max_tile_w = tile_w;
+	}
+	igt_remove_fb(data->drm_fd, &dummy);
+
+	/*
+	 * Pixman requires the stride to be aligned to 32-bits, which is
+	 * reflected in the initial value of max_tile_w and the hw
+	 * may require a multiple of tile width, choose biggest of the 2.
+	 */
+	*stride = ALIGN(*stride, max_tile_w);
+}
+
+static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
+				  uint32_t height, uint32_t format,
+				  uint64_t *modifier)
+{
+	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
+		/* Randomize the column height to less than twice the minimum.
+		 */
+		size_t column_height = (rand() % height) + height;
+
+		igt_debug(
+			"Selecting VC4 SAND256 tiling with column height %ld\n",
+			column_height);
+
+		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
+			column_height);
+	}
+}
+
+static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
+				  drmModeModeInfo *mode, uint32_t *width,
+				  uint32_t *height, uint32_t *format,
+				  uint64_t *modifier, bool allow_yuv)
+{
+	int min_dim;
+	uint32_t idx[plane->format_mod_count];
+	unsigned int count = 0;
+	unsigned int i;
+
+	/* First pass to count the supported formats. */
+	for (i = 0; i < plane->format_mod_count; i++)
+		if (igt_fb_supported_format(plane->formats[i]) &&
+		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
+			idx[count++] = i;
+
+	igt_assert(count > 0);
+
+	i = idx[rand() % count];
+	*format = plane->formats[i];
+	*modifier = plane->modifiers[i];
+
+	update_tiled_modifier(plane, *width, *height, *format, modifier);
+
+	/*
+	 * Randomize width and height in the mode dimensions range.
+	 *
+	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
+	 * least min_dim, because src_w = width - (rand % w / 2).
+	 *
+	 * Use a minimum dimension of 16 for YUV, because planar YUV
+	 * subsamples the UV plane.
+	 */
+	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
+
+	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
+	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
+}
+
+static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
+			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
+			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
+			    struct igt_fb *fb)
+{
+	igt_plane_set_fb(plane, fb);
+
+	igt_plane_set_position(plane, crtc_x, crtc_y);
+	igt_plane_set_size(plane, crtc_w, crtc_h);
+
+	igt_fb_set_position(fb, plane, src_x, src_y);
+	igt_fb_set_size(fb, plane, src_w, src_h);
+}
+
+static void randomize_plane_coordinates(
+	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
+	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
+	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
+	int32_t *crtc_y, bool allow_scaling)
+{
+	bool is_yuv = igt_format_is_yuv(fb->drm_format);
+	uint32_t width = fb->width, height = fb->height;
+	double ratio;
+	int ret;
+
+	/* Randomize source offset in the first half of the original size. */
+	*src_x = rand() % (width / 2);
+	*src_y = rand() % (height / 2);
+
+	/* The source size only includes the active source area. */
+	*src_w = width - *src_x;
+	*src_h = height - *src_y;
+
+	if (allow_scaling) {
+		*crtc_w = (rand() % mode->hdisplay) + 1;
+		*crtc_h = (rand() % mode->vdisplay) + 1;
+
+		/*
+		 * Don't bother with scaling if dimensions are quite close in
+		 * order to get non-scaling cases more frequently. Also limit
+		 * scaling to 3x to avoid aggressive filtering that makes
+		 * comparison less reliable, and don't go above 2x downsampling
+		 * to avoid possible hw limitations.
+		 */
+
+		ratio = ((double)*crtc_w / *src_w);
+		if (ratio < 0.5)
+			*src_w = *crtc_w * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_w = *src_w;
+		else if (ratio > 3.0)
+			*crtc_w = *src_w * 3;
+
+		ratio = ((double)*crtc_h / *src_h);
+		if (ratio < 0.5)
+			*src_h = *crtc_h * 2;
+		else if (ratio > 0.8 && ratio < 1.2)
+			*crtc_h = *src_h;
+		else if (ratio > 3.0)
+			*crtc_h = *src_h * 3;
+	} else {
+		*crtc_w = *src_w;
+		*crtc_h = *src_h;
+	}
+
+	if (*crtc_w != *src_w || *crtc_h != *src_h) {
+		/*
+		 * When scaling is involved, make sure to not go off-bounds or
+		 * scaled clipping may result in decimal dimensions, that most
+		 * drivers don't support.
+		 */
+		if (*crtc_w < mode->hdisplay)
+			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
+		else
+			*crtc_x = 0;
+
+		if (*crtc_h < mode->vdisplay)
+			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
+		else
+			*crtc_y = 0;
+	} else {
+		/*
+		 * Randomize the on-crtc position and allow the plane to go
+		 * off-display by less than half of its on-crtc dimensions.
+		 */
+		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
+		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
+	}
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	ret = igt_display_try_commit_atomic(
+		&data->display,
+		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
+		NULL);
+	if (!ret)
+		return;
+
+	/* Coordinates are logged in the dumped debug log, so only report w/h on
+	 * failure here. */
+	igt_assert_f(ret != -ENOSPC,
+		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
+		     width, height);
+
+	/* Make YUV coordinates a multiple of 2 and retry the math. */
+	if (is_yuv) {
+		*src_x &= ~1;
+		*src_y &= ~1;
+		*src_w &= ~1;
+		*src_h &= ~1;
+		/* To handle 1:1 scaling, clear crtc_w/h too. */
+		*crtc_w &= ~1;
+		*crtc_h &= ~1;
+
+		if (*crtc_x < 0 && (*crtc_x & 1))
+			(*crtc_x)++;
+		else
+			*crtc_x &= ~1;
+
+		/* If negative, round up to 0 instead of down */
+		if (*crtc_y < 0 && (*crtc_y & 1))
+			(*crtc_y)++;
+		else
+			*crtc_y &= ~1;
+
+		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
+				*crtc_h, *crtc_x, *crtc_y, fb);
+		ret = igt_display_try_commit_atomic(
+			&data->display,
+			DRM_MODE_ATOMIC_TEST_ONLY |
+				DRM_MODE_ATOMIC_ALLOW_MODESET,
+			NULL);
+		if (!ret)
+			return;
+	}
+
+	igt_assert(!ret || allow_scaling);
+	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
+		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
+
+	*crtc_w = *src_w;
+	*crtc_h = *src_h;
+
+	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
+			*crtc_x, *crtc_y, fb);
+	igt_display_commit_atomic(&data->display,
+				  DRM_MODE_ATOMIC_TEST_ONLY |
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+				  NULL);
+}
+
+static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
+			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
+			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
+			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
+{
+	cairo_surface_t *surface;
+	cairo_surface_t *clipped_surface;
+	cairo_t *cr;
+
+	surface = igt_get_cairo_surface(data->drm_fd, fb);
+
+	if (src_x || src_y) {
+		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+							     src_w, src_h);
+
+		cr = cairo_create(clipped_surface);
+
+		cairo_translate(cr, -1. * src_x, -1. * src_y);
+
+		cairo_set_source_surface(cr, surface, 0, 0);
+
+		cairo_paint(cr);
+		cairo_surface_flush(clipped_surface);
+
+		cairo_destroy(cr);
+	} else {
+		clipped_surface = surface;
+	}
+
+	cr = cairo_create(result);
+
+	cairo_translate(cr, crtc_x, crtc_y);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
+	}
+
+	cairo_set_source_surface(cr, clipped_surface, 0, 0);
+	cairo_surface_destroy(clipped_surface);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		cairo_pattern_set_filter(cairo_get_source(cr),
+					 CAIRO_FILTER_BILINEAR);
+		cairo_pattern_set_extend(cairo_get_source(cr),
+					 CAIRO_EXTEND_NONE);
+	}
+
+	cairo_paint(cr);
+	cairo_surface_flush(result);
+
+	cairo_destroy(cr);
+}
+
+static void prepare_randomized_plane(chamelium_data_t *data,
+				     drmModeModeInfo *mode, igt_plane_t *plane,
+				     struct igt_fb *overlay_fb,
+				     unsigned int index,
+				     cairo_surface_t *result_surface,
+				     bool allow_scaling, bool allow_yuv)
+{
+	struct igt_fb pattern_fb;
+	uint32_t overlay_fb_w, overlay_fb_h;
+	uint32_t overlay_src_w, overlay_src_h;
+	uint32_t overlay_src_x, overlay_src_y;
+	int32_t overlay_crtc_x, overlay_crtc_y;
+	uint32_t overlay_crtc_w, overlay_crtc_h;
+	uint32_t format;
+	uint64_t modifier;
+	size_t stride;
+	bool tiled;
+	int fb_id;
+
+	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
+			      &format, &modifier, allow_yuv);
+
+	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
+	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
+		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
+		  tiled ? "tiled" : "linear");
+
+	/* Get a pattern framebuffer for the overlay plane. */
+	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
+					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
+			       modifier, &stride);
+
+	igt_debug("Plane %d: stride %ld\n", index, stride);
+
+	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
+					   modifier, stride);
+	igt_assert(fb_id > 0);
+
+	randomize_plane_coordinates(data, plane, mode, overlay_fb,
+				    &overlay_src_w, &overlay_src_h,
+				    &overlay_src_x, &overlay_src_y,
+				    &overlay_crtc_w, &overlay_crtc_h,
+				    &overlay_crtc_x, &overlay_crtc_y,
+				    allow_scaling);
+
+	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
+		  overlay_src_h);
+	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
+		  overlay_src_x, overlay_src_y);
+	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
+		  overlay_crtc_h);
+	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
+		  overlay_crtc_y);
+
+	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
+			 overlay_src_x, overlay_src_y, overlay_crtc_w,
+			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
+			 &pattern_fb);
+
+	/* Remove the original pattern framebuffer. */
+	igt_remove_fb(data->drm_fd, &pattern_fb);
+}
+
+static const char test_display_one_mode_desc[] =
+	"Pick the first mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_one_mode(chamelium_data_t *data,
+				  struct chamelium_port *port, uint32_t fourcc,
+				  enum chamelium_check check, int count)
+{
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	igt_output_t *output;
+	igt_plane_t *primary;
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	igt_require(igt_plane_has_format_mod(primary, fourcc,
+					     DRM_FORMAT_MOD_LINEAR));
+
+	mode = &connector->modes[0];
+	if (check == CHAMELIUM_CHECK_ANALOG) {
+		bool bridge = chamelium_check_analog_bridge(data, port);
+
+		igt_assert(!(bridge && prune_vga_mode(data, mode)));
+	}
+
+	do_test_display(data, port, output, mode, fourcc, check, count);
+
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_all_modes_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then check captured frames are correct";
+static void test_display_all_modes(chamelium_data_t *data,
+				   struct chamelium_port *port, uint32_t fourcc,
+				   enum chamelium_check check, int count)
+{
+	bool bridge;
+	int i, count_modes;
+
+	if (check == CHAMELIUM_CHECK_ANALOG)
+		bridge = chamelium_check_analog_bridge(data, port);
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		drmModeConnector *connector;
+		drmModeModeInfo *mode;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+		igt_require(igt_plane_has_format_mod(primary, fourcc,
+						     DRM_FORMAT_MOD_LINEAR));
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
+		    prune_vga_mode(data, mode))
+			continue;
+
+		do_test_display(data, port, output, mode, fourcc, check, count);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_frame_dump_desc[] =
+	"For each mode of the IGT base EDID, display and capture a few "
+	"frames, then download the captured frames and compare them "
+	"bit-by-bit to the sent ones";
+static void test_display_frame_dump(chamelium_data_t *data,
+				    struct chamelium_port *port)
+{
+	int i, count_modes;
+
+	i = 0;
+	do {
+		igt_output_t *output;
+		igt_plane_t *primary;
+		struct igt_fb fb;
+		struct chamelium_frame_dump *frame;
+		drmModeModeInfo *mode;
+		drmModeConnector *connector;
+		int fb_id, j;
+
+		/*
+		 * let's reset state each mode so we will get the
+		 * HPD pulses realibably
+		 */
+		igt_modeset_disable_all_outputs(&data->display);
+		chamelium_reset_state(&data->display, data->chamelium, port,
+				      data->ports, data->port_count);
+
+		/*
+		 * modes may change due to mode pruining and link issues, so we
+		 * need to refresh the connector
+		 */
+		output = chamelium_prepare_output(data, port,
+						  IGT_CUSTOM_EDID_BASE);
+		connector = chamelium_port_get_connector(data->chamelium, port,
+							 false);
+		primary = igt_output_get_plane_type(output,
+						    DRM_PLANE_TYPE_PRIMARY);
+		igt_assert(primary);
+
+		/* we may skip some modes due to above but that's ok */
+		count_modes = connector->count_modes;
+		if (i >= count_modes)
+			break;
+
+		mode = &connector->modes[i];
+
+		fb_id = igt_create_color_pattern_fb(
+			data->drm_fd, mode->hdisplay, mode->vdisplay,
+			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+			&fb);
+		igt_assert(fb_id > 0);
+
+		chamelium_enable_output(data, port, output, mode, &fb);
+
+		igt_debug("Reading frame dumps from Chamelium...\n");
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
+		for (j = 0; j < 5; j++) {
+			frame = chamelium_read_captured_frame(data->chamelium,
+							      j);
+			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
+			chamelium_destroy_frame_dump(frame);
+		}
+
+		igt_remove_fb(data->drm_fd, &fb);
+		drmModeFreeConnector(connector);
+	} while (++i < count_modes);
+}
+
+static const char test_display_aspect_ratio_desc[] =
+	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
+	"check they include the relevant fields";
+static void test_display_aspect_ratio(chamelium_data_t *data,
+				      struct chamelium_port *port)
+{
+	igt_output_t *output;
+	igt_plane_t *primary;
+	drmModeConnector *connector;
+	drmModeModeInfo *mode;
+	int fb_id, i;
+	struct igt_fb fb;
+	bool found, ok;
+	struct chamelium_infoframe *infoframe;
+	struct infoframe_avi infoframe_avi;
+	uint8_t vic = 16; /* TODO: test more VICs */
+	const struct vic_mode *vic_mode;
+	uint32_t aspect_ratio;
+	enum infoframe_avi_picture_aspect_ratio frame_ar;
+
+	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	output = chamelium_prepare_output(data, port,
+					  IGT_CUSTOM_EDID_ASPECT_RATIO);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	vic_mode = &vic_modes[vic];
+	aspect_ratio = vic_mode->picture_ar;
+
+	found = false;
+	igt_assert(connector->count_modes > 0);
+	for (i = 0; i < connector->count_modes; i++) {
+		mode = &connector->modes[i];
+
+		if (vic_mode_matches_drm(vic_mode, mode)) {
+			found = true;
+			break;
+		}
+	}
+	igt_assert_f(found,
+		     "Failed to find mode with the correct aspect ratio\n");
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
+					    mode->vdisplay, DRM_FORMAT_XRGB8888,
+					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
+					    &fb);
+	igt_assert(fb_id > 0);
+
+	chamelium_enable_output(data, port, output, mode, &fb);
+
+	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
+						 CHAMELIUM_INFOFRAME_AVI);
+	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
+
+	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
+				 infoframe->payload, infoframe->payload_size);
+	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
+
+	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
+
+	igt_debug("Checking AVI InfoFrame\n");
+	igt_debug("Picture aspect ratio: got %d, expected %d\n",
+		  infoframe_avi.picture_aspect_ratio, frame_ar);
+	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
+		  infoframe_avi.vic, vic);
+
+	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
+	igt_assert(infoframe_avi.vic == vic);
+
+	chamelium_infoframe_destroy(infoframe);
+	igt_remove_fb(data->drm_fd, &fb);
+	drmModeFreeConnector(connector);
+}
+
+static const char test_display_planes_random_desc[] =
+	"Setup a few overlay planes with random parameters, capture the frame "
+	"and check it matches the expected output";
+static void test_display_planes_random(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum chamelium_check check)
+{
+	igt_output_t *output;
+	drmModeModeInfo *mode;
+	igt_plane_t *primary_plane;
+	struct igt_fb primary_fb;
+	struct igt_fb result_fb;
+	struct igt_fb *overlay_fbs;
+	igt_crc_t *crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
+	unsigned int overlay_planes_max = 0;
+	unsigned int overlay_planes_count;
+	cairo_surface_t *result_surface;
+	int captured_frame_count;
+	bool allow_scaling;
+	bool allow_yuv;
+	unsigned int i;
+	unsigned int fb_id;
+
+	switch (check) {
+	case CHAMELIUM_CHECK_CRC:
+		allow_scaling = false;
+		allow_yuv = false;
+		break;
+	case CHAMELIUM_CHECK_CHECKERBOARD:
+		allow_scaling = true;
+		allow_yuv = true;
+		break;
+	default:
+		igt_assert(false);
+	}
+
+	srand(time(NULL));
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Find the connector and pipe. */
+	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
+
+	mode = igt_output_get_mode(output);
+
+	/* Get a framebuffer for the primary plane. */
+	primary_plane =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary_plane);
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
+	igt_assert(fb_id > 0);
+
+	/* Get a framebuffer for the cairo composition result. */
+	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
+			      &result_fb);
+	igt_assert(fb_id > 0);
+
+	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
+
+	/* Paint the primary framebuffer on the result surface. */
+	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
+			 &primary_fb);
+
+	/* Configure the primary plane. */
+	igt_plane_set_fb(primary_plane, &primary_fb);
+
+	overlay_planes_max =
+		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
+
+	/* Limit the number of planes to a reasonable scene. */
+	overlay_planes_max = min(overlay_planes_max, 4u);
+
+	overlay_planes_count = (rand() % overlay_planes_max) + 1;
+	igt_debug("Using %d overlay planes\n", overlay_planes_count);
+
+	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
+
+	for (i = 0; i < overlay_planes_count; i++) {
+		struct igt_fb *overlay_fb = &overlay_fbs[i];
+		igt_plane_t *plane = igt_output_get_plane_type_index(
+			output, DRM_PLANE_TYPE_OVERLAY, i);
+		igt_assert(plane);
+
+		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
+					 result_surface, allow_scaling,
+					 allow_yuv);
+	}
+
+	cairo_surface_destroy(result_surface);
+
+	if (check == CHAMELIUM_CHECK_CRC)
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&result_fb);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	if (check == CHAMELIUM_CHECK_CRC) {
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
+
+		igt_assert(captured_frame_count == 1);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &result_fb, 0);
+
+		free(expected_crc);
+		free(crc);
+	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
+		struct chamelium_frame_dump *dump;
+
+		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
+						  0, 0);
+		chamelium_assert_frame_match_or_dump(data->chamelium, port,
+						     dump, &result_fb, check);
+		chamelium_destroy_frame_dump(dump);
+	}
+
+	for (i = 0; i < overlay_planes_count; i++)
+		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
+
+	free(overlay_fbs);
+
+	igt_remove_fb(data->drm_fd, &primary_fb);
+	igt_remove_fb(data->drm_fd, &result_fb);
+}
+
+IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-single", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("dp-crc-fast", DisplayPort)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("dp-crc-multiple", DisplayPort)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("dp-frame-dump", DisplayPort)
+			test_display_frame_dump(&data, port);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-single", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_subtest("hdmi-crc-fast", HDMIA)
+			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
+					      CHAMELIUM_CHECK_CRC, 1);
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("hdmi-crc-multiple", HDMIA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_CRC, 3);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CRC, 1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-crc-planes-random", HDMIA)
+			test_display_planes_random(&data, port,
+						   CHAMELIUM_CHECK_CRC);
+
+		igt_describe(test_display_one_mode_desc);
+		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
+		{
+			int k;
+			igt_output_t *output;
+			igt_plane_t *primary;
+
+			output = chamelium_prepare_output(&data, port,
+							  IGT_CUSTOM_EDID_BASE);
+			primary = igt_output_get_plane_type(
+				output, DRM_PLANE_TYPE_PRIMARY);
+			igt_assert(primary);
+
+			for (k = 0; k < primary->format_mod_count; k++) {
+				if (!igt_fb_supported_format(
+					    primary->formats[k]))
+					continue;
+
+				if (!igt_format_is_yuv(primary->formats[k]))
+					continue;
+
+				if (primary->modifiers[k] !=
+				    DRM_FORMAT_MOD_LINEAR)
+					continue;
+
+				igt_dynamic_f(
+					"%s",
+					igt_format_str(primary->formats[k]))
+					test_display_one_mode(
+						&data, port,
+						primary->formats[k],
+						CHAMELIUM_CHECK_CHECKERBOARD,
+						1);
+			}
+		}
+
+		igt_describe(test_display_planes_random_desc);
+		connector_subtest("hdmi-cmp-planes-random", HDMIA)
+			test_display_planes_random(
+				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
+
+		igt_describe(test_display_frame_dump_desc);
+		connector_subtest("hdmi-frame-dump", HDMIA)
+			test_display_frame_dump(&data, port);
+
+		igt_describe(test_display_aspect_ratio_desc);
+		connector_subtest("hdmi-aspect-ratio", HDMIA)
+			test_display_aspect_ratio(&data, port);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_display_all_modes_desc);
+		connector_subtest("vga-frame-dump", VGA)
+			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
+					       CHAMELIUM_CHECK_ANALOG, 1);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
new file mode 100644
index 00000000..b9544288
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "igt_edid.h"
+#include "kms_chamelium_helper.h"
+
+void chamelium_init_test(chamelium_data_t *data)
+{
+	int i;
+
+	/* So fbcon doesn't try to reprobe things itself */
+	kmstest_set_vt_graphics_mode();
+
+	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
+	igt_display_require(&data->display, data->drm_fd);
+	igt_require(data->display.is_atomic);
+
+	/*
+	 * XXX: disabling modeset, can be removed when
+	 * igt_display_require will start doing this for us
+	 */
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	/* we need to initalize chamelium after igt_display_require */
+	data->chamelium = chamelium_init(data->drm_fd, &data->display);
+	igt_require(data->chamelium);
+
+	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
+
+	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
+		data->edids[i] = chamelium_new_edid(data->chamelium,
+						    igt_kms_get_custom_edid(i));
+	}
+}
+
+/* Wait for hotplug and return the remaining time left from timeout */
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
+{
+	struct timespec start, end;
+	int elapsed;
+	bool detected;
+
+	igt_assert_eq(igt_gettime(&start), 0);
+	detected = igt_hotplug_detected(mon, *timeout);
+	igt_assert_eq(igt_gettime(&end), 0);
+
+	elapsed = igt_time_elapsed(&start, &end);
+	igt_assert_lte(0, elapsed);
+	*timeout = max(0, *timeout - elapsed);
+
+	return detected;
+}
+
+/**
+ * chamelium_wait_for_connector_after_hotplug:
+ *
+ * Waits for the connector attached to @port to have a status of @status after
+ * it's plugged/unplugged.
+ *
+ */
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status)
+{
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int hotplug_count = 0;
+
+	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
+		  chamelium_port_get_name(port),
+		  kmstest_connector_status_str(status));
+
+	while (timeout > 0) {
+		if (!chamelium_wait_for_hotplug(mon, &timeout))
+			break;
+
+		hotplug_count++;
+
+		if (chamelium_reprobe_connector(&data->display, data->chamelium,
+						port) == status)
+			return;
+	}
+
+	igt_assert_f(
+		false,
+		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
+		chamelium_port_get_name(port),
+		kmstest_connector_status_str(status),
+		kmstest_connector_status_str(chamelium_reprobe_connector(
+			&data->display, data->chamelium, port)),
+		hotplug_count);
+}
+
+/**
+ * chamelium_port_get_connector:
+ * @data: The Chamelium data instance to use
+ * @port: The chamelium port to prepare its connector
+ * @edid: The chamelium's default EDID has a lot of resolutions, way more then
+ * 		  we need to test. Additionally the default EDID doesn't support
+ *        HDMI audio.
+ *
+ * Makes sure the output display of the connector attached to @port is connected
+ * and ready for use.
+ *
+ * Returns: a pointer to the enabled igt_output_t
+ */
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	/* The chamelium's default EDID has a lot of resolutions, way more then
+	 * we need to test. Additionally the default EDID doesn't support HDMI
+	 * audio.
+	 */
+	chamelium_set_edid(data, port, edid);
+
+	chamelium_plug(data->chamelium, port);
+	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
+					      port, DRM_MODE_CONNECTED);
+
+	igt_display_reset(display);
+
+	output = chamelium_get_output_for_port(data, port);
+
+	/* Refresh pipe to update connected status */
+	igt_output_set_pipe(output, PIPE_NONE);
+
+	pipe = chamelium_get_pipe_for_output(display, output);
+	igt_output_set_pipe(output, pipe);
+
+	return output;
+}
+
+/**
+ * chamelium_enable_output:
+ *
+ * Modesets the connector attached to @port for the assigned @mode and draws the
+ * @fb.
+ *
+ */
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb)
+{
+	igt_display_t *display = output->display;
+	igt_plane_t *primary =
+		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+
+	igt_assert(primary);
+
+	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
+	igt_plane_set_fb(primary, fb);
+	igt_output_override_mode(output, mode);
+
+	/* Clear any color correction values that might be enabled */
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
+		igt_pipe_obj_replace_prop_blob(primary->pipe,
+					       IGT_CRTC_GAMMA_LUT, NULL, 0);
+	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
+		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
+					       NULL, 0);
+
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
+		usleep(250000);
+
+	drmModeFreeConnector(connector);
+}
+
+/* Return pipe attached to @outpu.t */
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output)
+{
+	enum pipe pipe;
+
+	for_each_pipe(display, pipe) {
+		if (igt_pipe_connector_valid(pipe, output)) {
+			return pipe;
+		}
+	}
+
+	igt_assert_f(false, "No pipe found for output %s\n",
+		     igt_output_name(output));
+}
+
+static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
+					 size_t height, size_t stride,
+					 size_t block_size)
+{
+	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
+			      0xffffffff };
+	unsigned i, j;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			*(data + i * stride / 4 +
+			  j) = colors[((j / block_size) + (i / block_size)) % 5];
+}
+
+/**
+ * chamelium_get_pattern_fb:
+ *
+ * Creates an @fb with an xr24 pattern and returns the fb_id.
+ *
+ */
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb)
+{
+	int fb_id;
+	void *ptr;
+
+	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
+
+	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
+			      DRM_FORMAT_MOD_LINEAR, fb);
+	igt_assert(fb_id > 0);
+
+	ptr = igt_fb_map_buffer(fb->fd, fb);
+	igt_assert(ptr);
+
+	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
+				     block_size);
+	igt_fb_unmap_buffer(fb, ptr);
+
+	return fb_id;
+}
+
+/* Generate a simple @fb for the size of @mode. */
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode)
+{
+	int fb_id;
+
+	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
+					 DRM_FORMAT_XRGB8888, 64, fb);
+
+	igt_assert(fb_id > 0);
+}
+
+/* Returns the first preferred mode for the connector attached to @port. */
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(chamelium, port, false);
+	drmModeModeInfo mode;
+	igt_assert(&connector->modes[0] != NULL);
+	memcpy(&mode, &connector->modes[0], sizeof(mode));
+	drmModeFreeConnector(connector);
+	return mode;
+}
+
+/* Returns the igt display output for the connector attached to @port. */
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port)
+{
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, true);
+	igt_output_t *output =
+		igt_output_from_connector(&data->display, connector);
+	drmModeFreeConnector(connector);
+	igt_assert(output != NULL);
+	return output;
+}
+
+/* Set the EDID of index @edid to Chamelium's @port. */
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid)
+{
+	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
+}
+
+/**
+ * chamelium_check_analog_bridge:
+ *
+ * Check if the connector associalted to @port is an analog bridge by checking
+ * if it has its own EDID.
+ *
+ */
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port)
+{
+	drmModePropertyBlobPtr edid_blob = NULL;
+	drmModeConnector *connector =
+		chamelium_port_get_connector(data->chamelium, port, false);
+	uint64_t edid_blob_id;
+	const struct edid *edid;
+	char edid_vendor[3];
+
+	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
+		drmModeFreeConnector(connector);
+		return false;
+	}
+
+	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
+					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
+					&edid_blob_id, NULL));
+	igt_assert(edid_blob =
+			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
+
+	edid = (const struct edid *)edid_blob->data;
+	edid_get_mfg(edid, edid_vendor);
+
+	drmModeFreePropertyBlob(edid_blob);
+	drmModeFreeConnector(connector);
+
+	/* Analog bridges provide their own EDID */
+	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
+	    edid_vendor[2] != 'T')
+		return true;
+
+	return false;
+}
\ No newline at end of file
diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
new file mode 100644
index 00000000..09fa4829
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_helper.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * A helper library for all Chamelium tests.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
+
+#include "igt.h"
+
+#define ONLINE_TIMEOUT 20 /* seconds */
+
+#define for_each_port(p, port)                                 \
+	for (p = 0, port = data.ports[p]; p < data.port_count; \
+	     p++, port = data.ports[p])
+
+#define connector_subtest(name__, type__)                           \
+	igt_subtest(name__)                                         \
+	for_each_port(p, port) if (chamelium_port_get_type(port) == \
+				   DRM_MODE_CONNECTOR_##type__)
+
+/*
+ * The chamelium data structure is used to store all the information known about
+ * chamelium to run the tests.
+ */
+typedef struct {
+	struct chamelium *chamelium;
+	struct chamelium_port **ports;
+	igt_display_t display;
+	int port_count;
+
+	int drm_fd;
+
+	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
+} chamelium_data_t;
+
+void chamelium_init_test(chamelium_data_t *data);
+
+bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
+void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
+						struct udev_monitor *mon,
+						struct chamelium_port *port,
+						drmModeConnection status);
+
+igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
+				       struct chamelium_port *port,
+				       enum igt_custom_edid_type edid);
+void chamelium_enable_output(chamelium_data_t *data,
+			     struct chamelium_port *port, igt_output_t *output,
+			     drmModeModeInfo *mode, struct igt_fb *fb);
+enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
+					igt_output_t *output);
+
+int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
+			     size_t height, uint32_t fourcc, size_t block_size,
+			     struct igt_fb *fb);
+void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
+				  drmModeModeInfo *mode);
+drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
+					    struct chamelium_port *port);
+igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
+					    struct chamelium_port *port);
+
+void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
+			enum igt_custom_edid_type edid);
+
+bool chamelium_check_analog_bridge(chamelium_data_t *data,
+				   struct chamelium_port *port);
+
+#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
new file mode 100644
index 00000000..8a4e1aba
--- /dev/null
+++ b/tests/chamelium/kms_chamelium_hpd.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: MIT
+/*
+ * A Chamelium test for testing the HPD functionality.
+ *
+ * Copyright 2022 Google LLC.
+ *
+ * Authors: Mark Yacoub <markyacoub@chromium.org>
+ */
+
+#include "kms_chamelium_helper.h"
+
+#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
+#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
+
+#define HPD_TOGGLE_COUNT_VGA 5
+#define HPD_TOGGLE_COUNT_DP_HDMI 15
+#define HPD_TOGGLE_COUNT_FAST 3
+
+enum test_modeset_mode {
+	TEST_MODESET_ON,
+	TEST_MODESET_ON_OFF,
+	TEST_MODESET_OFF,
+};
+
+static void try_suspend_resume_hpd(chamelium_data_t *data,
+				   struct chamelium_port *port,
+				   enum igt_suspend_state state,
+				   enum igt_suspend_test test,
+				   struct udev_monitor *mon, bool connected)
+{
+	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
+						     DRM_MODE_CONNECTED;
+	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
+	int delay;
+	int p;
+
+	igt_flush_uevents(mon);
+
+	delay = igt_get_autoresume_delay(state) * 1000 / 2;
+
+	if (port) {
+		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
+					      !connected);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			port = data->ports[p];
+			chamelium_schedule_hpd_toggle(data->chamelium, port,
+						      delay, !connected);
+		}
+
+		port = NULL;
+	}
+
+	igt_system_suspend_autoresume(state, test);
+	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
+
+	if (port) {
+		igt_assert_eq(chamelium_reprobe_connector(
+				      &data->display, data->chamelium, port),
+			      target_state);
+	} else {
+		for (p = 0; p < data->port_count; p++) {
+			drmModeConnection current_state;
+
+			port = data->ports[p];
+			/*
+			 * There could be as many hotplug events sent by
+			 * driver as connectors we scheduled an HPD toggle on
+			 * above, depending on timing. So if we're not seeing
+			 * the expected connector state try to wait for an HPD
+			 * event for each connector/port.
+			 */
+			current_state = chamelium_reprobe_connector(
+				&data->display, data->chamelium, port);
+			if (p > 0 && current_state != target_state) {
+				igt_assert(chamelium_wait_for_hotplug(
+					mon, &timeout));
+				current_state = chamelium_reprobe_connector(
+					&data->display, data->chamelium, port);
+			}
+
+			igt_assert_eq(current_state, target_state);
+		}
+
+		port = NULL;
+	}
+}
+
+static const char test_basic_hotplug_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug";
+static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
+			 int toggle_count, enum test_modeset_mode modeset_mode)
+{
+	int i;
+	enum pipe pipe;
+	struct igt_fb fb = { 0 };
+	drmModeModeInfo mode;
+	struct udev_monitor *mon = igt_watch_uevents();
+	igt_output_t *output = chamelium_get_output_for_port(data, port);
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+
+	for (i = 0; i < toggle_count; i++) {
+		igt_flush_uevents(mon);
+
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF ||
+		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
+			if (i == 0) {
+				/* We can only get mode and pipe once we are
+				 * connected */
+				output = chamelium_get_output_for_port(data,
+								       port);
+				pipe = chamelium_get_pipe_for_output(
+					&data->display, output);
+				mode = chamelium_get_mode_for_port(
+					data->chamelium, port);
+				chamelium_create_fb_for_mode(data, &fb, &mode);
+			}
+
+			igt_output_set_pipe(output, pipe);
+			chamelium_enable_output(data, port, output, &mode, &fb);
+		}
+
+		/* Now check if we get a hotplug from disconnection */
+		chamelium_unplug(data->chamelium, port);
+
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+
+		igt_flush_uevents(mon);
+
+		if (modeset_mode == TEST_MODESET_ON_OFF) {
+			igt_output_set_pipe(output, PIPE_NONE);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static const char test_hotplug_for_each_pipe_desc[] =
+	"Check that we get uevents and updated connector status on "
+	"hotplug and unplug for each pipe with valid output";
+static void test_hotplug_for_each_pipe(chamelium_data_t *data,
+				       struct chamelium_port *port)
+{
+	igt_output_t *output;
+	enum pipe pipe;
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	/* Disconnect if any port got connected */
+	chamelium_unplug(data->chamelium, port);
+	chamelium_wait_for_connector_after_hotplug(data, mon, port,
+						   DRM_MODE_DISCONNECTED);
+
+	for_each_pipe(&data->display, pipe) {
+		igt_flush_uevents(mon);
+		/* Check if we get a sysfs hotplug event */
+		chamelium_plug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(data, mon, port,
+							   DRM_MODE_CONNECTED);
+		igt_flush_uevents(mon);
+		output = chamelium_get_output_for_port(data, port);
+
+		/* If pipe is valid for output then set it */
+		if (igt_pipe_connector_valid(pipe, output)) {
+			igt_output_set_pipe(output, pipe);
+			igt_display_commit2(&data->display, COMMIT_ATOMIC);
+		}
+
+		chamelium_unplug(data->chamelium, port);
+		chamelium_wait_for_connector_after_hotplug(
+			data, mon, port, DRM_MODE_DISCONNECTED);
+		igt_flush_uevents(mon);
+	}
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_suspend_resume_hpd_desc[] =
+	"Toggle HPD during suspend, check that uevents are sent and connector "
+	"status is updated";
+static void test_suspend_resume_hpd(chamelium_data_t *data,
+				    struct chamelium_port *port,
+				    enum igt_suspend_state state,
+				    enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, port, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_suspend_resume_hpd_common_desc[] =
+	"Toggle HPD during suspend on all connectors, check that uevents are "
+	"sent and connector status is updated";
+static void test_suspend_resume_hpd_common(chamelium_data_t *data,
+					   enum igt_suspend_state state,
+					   enum igt_suspend_test test)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+	struct chamelium_port *port;
+	int p;
+
+	for (p = 0; p < data->port_count; p++) {
+		port = data->ports[p];
+		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
+	}
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, NULL,
+			      data->ports, data->port_count);
+
+	/* Make sure we notice new connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
+
+	/* Now make sure we notice disconnected connectors after resuming */
+	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_without_ddc_desc[] =
+	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
+static void test_hpd_without_ddc(chamelium_data_t *data,
+				 struct chamelium_port *port)
+{
+	struct udev_monitor *mon = igt_watch_uevents();
+
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+	igt_flush_uevents(mon);
+
+	/* Disable the DDC on the connector and make sure we still get a
+	 * hotplug
+	 */
+	chamelium_port_set_ddc_state(data->chamelium, port, false);
+	chamelium_plug(data->chamelium, port);
+
+	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
+	igt_assert_eq(chamelium_reprobe_connector(&data->display,
+						  data->chamelium, port),
+		      DRM_MODE_CONNECTED);
+
+	igt_cleanup_uevents(mon);
+}
+
+static const char test_hpd_storm_detect_desc[] =
+	"Trigger a series of hotplugs in a very small timeframe to simulate a"
+	"bad cable, check the kernel falls back to polling to avoid a hotplug "
+	"storm";
+static void test_hpd_storm_detect(chamelium_data_t *data,
+				  struct chamelium_port *port, int width)
+{
+	struct udev_monitor *mon;
+	int count = 0;
+
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 1);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(igt_hpd_storm_detected(data->drm_fd));
+
+	mon = igt_watch_uevents();
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+
+	/*
+	 * Polling should have been enabled by the HPD storm at this point,
+	 * so we should only get at most 1 hotplug event
+	 */
+	igt_until_timeout(5)
+		count += igt_hotplug_detected(mon, 1);
+	igt_assert_lt(count, 2);
+
+	igt_cleanup_uevents(mon);
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+static const char test_hpd_storm_disable_desc[] =
+	"Disable HPD storm detection, trigger a storm and check the kernel "
+	"doesn't detect one";
+static void test_hpd_storm_disable(chamelium_data_t *data,
+				   struct chamelium_port *port, int width)
+{
+	igt_require_hpd_storm_ctl(data->drm_fd);
+	igt_modeset_disable_all_outputs(&data->display);
+	chamelium_reset_state(&data->display, data->chamelium, port,
+			      data->ports, data->port_count);
+
+	igt_hpd_storm_set_threshold(data->drm_fd, 0);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
+
+	igt_hpd_storm_reset(data->drm_fd);
+}
+
+IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
+igt_main
+{
+	chamelium_data_t data;
+	struct chamelium_port *port;
+	int p;
+
+	igt_fixture {
+		chamelium_init_test(&data);
+	}
+
+	igt_describe("DisplayPort tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-suspend", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("dp-hpd-storm", DisplayPort)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_DP);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("dp-hpd-storm-disable", DisplayPort)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_DP);
+	}
+
+	igt_describe("HDMI tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_HDMIA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
+				     TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_hotplug_for_each_pipe_desc);
+		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
+			test_hotplug_for_each_pipe(&data, port);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_storm_detect_desc);
+		connector_subtest("hdmi-hpd-storm", HDMIA)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_HDMI);
+
+		igt_describe(test_hpd_storm_disable_desc);
+		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_HDMI);
+	}
+
+	igt_describe("VGA tests");
+	igt_subtest_group {
+		igt_fixture {
+			chamelium_require_connector_present(
+				data.ports, DRM_MODE_CONNECTOR_VGA,
+				data.port_count, 1);
+		}
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
+			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-enable-disable-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON_OFF);
+
+		igt_describe(test_basic_hotplug_desc);
+		connector_subtest("vga-hpd-with-enabled-mode", VGA)
+			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
+				     TEST_MODESET_ON);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-suspend", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
+						SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_desc);
+		connector_subtest("vga-hpd-after-hibernate", VGA)
+			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
+						SUSPEND_TEST_DEVICES);
+
+		igt_describe(test_hpd_without_ddc_desc);
+		connector_subtest("vga-hpd-without-ddc", VGA)
+			test_hpd_without_ddc(&data, port);
+	}
+
+	igt_describe("Tests that operate on all connectors");
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(data.port_count);
+		}
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-suspend")
+			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
+						       SUSPEND_TEST_NONE);
+
+		igt_describe(test_suspend_resume_hpd_common_desc);
+		igt_subtest("common-hpd-after-hibernate")
+			test_suspend_resume_hpd_common(&data,
+						       SUSPEND_STATE_DISK,
+						       SUSPEND_TEST_DEVICES);
+	}
+
+	igt_describe(test_hotplug_for_each_pipe_desc);
+	connector_subtest("vga-hpd-for-each-pipe", VGA)
+		test_hotplug_for_each_pipe(&data, port);
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 0d307730..6e5cc436 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
 # is too costly in comparison to the value
 # provided.
 ###############################################
-igt@kms_chamelium@hdmi-.*-planes-random
+igt@kms_chamelium_frames@hdmi-.*-planes-random
 ###############################################
 # Broadcom
 ###############################################
diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index f57f8ff3..fb4c0f73 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
 igt@kms_addfb_basic@unused-offsets
 igt@kms_addfb_basic@unused-pitches
 igt@kms_busy@basic
-igt@kms_chamelium@dp-hpd-fast
-igt@kms_chamelium@dp-edid-read
-igt@kms_chamelium@dp-crc-fast
-igt@kms_chamelium@hdmi-hpd-fast
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@vga-hpd-fast
-igt@kms_chamelium@vga-edid-read
+igt@kms_chamelium_hpd@dp-hpd-fast
+igt@kms_chamelium_edid@dp-edid-read
+igt@kms_chamelium_frames@dp-crc-fast
+igt@kms_chamelium_hpd@hdmi-hpd-fast
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_hpd@vga-hpd-fast
+igt@kms_chamelium_edid@vga-edid-read
 igt@kms_prop_blob@basic
 igt@kms_cursor_legacy@basic-busy-flip-before-cursor
 igt@kms_cursor_legacy@basic-flip-after-cursor
@@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
 igt@i915_suspend@basic-s3-without-i915
 igt@gem_exec_suspend@basic-s0
 igt@gem_exec_suspend@basic-s3
-igt@kms_chamelium@common-hpd-after-suspend
+igt@kms_chamelium_hpd@common-hpd-after-suspend
 igt@kms_pipe_crc_basic@suspend-read-crc
diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
index f0ae30e3..f9242232 100644
--- a/tests/kms_color_helper.h
+++ b/tests/kms_color_helper.h
@@ -27,7 +27,7 @@
 
 /*
  * This header is for code that is shared between kms_color.c and
- * kms_color_chamelium.c. Reusability elsewhere can be questionable.
+ * kms_chamelium_color.c. Reusability elsewhere can be questionable.
  */
 
 #include <math.h>
diff --git a/tests/meson.build b/tests/meson.build
index 5c052e73..b52399d5 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -260,7 +260,10 @@ msm_progs = [
 ]
 
 chamelium_progs = [
-	'kms_chamelium',
+	'kms_chamelium_audio',
+	'kms_chamelium_edid',
+	'kms_chamelium_frames',
+	'kms_chamelium_hpd',
 ]
 
 test_deps = [ igt_deps ]
@@ -309,7 +312,8 @@ endforeach
 if chamelium.found()
 	foreach prog : chamelium_progs
 		test_executables += executable(prog,
-				 join_paths('chamelium', prog + '.c'),
+				 [join_paths('chamelium', prog + '.c'), 
+				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
 				 dependencies : test_deps,
 				 install_dir : libexecdir,
 				 install_rpath : libexecdir_rpathdir,
@@ -436,13 +440,13 @@ test_executables += executable('kms_color',
 test_list += 'kms_color'
 
 if chamelium.found()
-       test_executables += executable('kms_color_chamelium',
-                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
+       test_executables += executable('kms_chamelium_color',
+                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
                              dependencies : test_deps + [ chamelium ],
                              install_dir : libexecdir,
                              install_rpath : libexecdir_rpathdir,
                              install : true)
-       test_list += 'kms_color_chamelium'
+       test_list += 'kms_chamelium_color'
 endif
 
 test_executables += executable('sw_sync', 'sw_sync.c',
diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
index dd45d12a..a5521021 100644
--- a/tests/vc4_ci/vc4-chamelium-fast.testlist
+++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
@@ -1,14 +1,14 @@
-igt@kms_chamelium@hdmi-crc-abgr8888
-igt@kms_chamelium@hdmi-crc-argb1555
-igt@kms_chamelium@hdmi-crc-argb8888
-igt@kms_chamelium@hdmi-crc-bgr565
-igt@kms_chamelium@hdmi-crc-bgr888
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@hdmi-crc-rgb565
-igt@kms_chamelium@hdmi-crc-rgb888
-igt@kms_chamelium@hdmi-crc-xbgr8888
-igt@kms_chamelium@hdmi-crc-xrgb1555
-igt@kms_chamelium@hdmi-crc-xrgb8888
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-hpd
-igt@kms_chamelium@hdmi-hpd-fast
+igt@kms_chamelium_frames@hdmi-crc-abgr8888
+igt@kms_chamelium_frames@hdmi-crc-argb1555
+igt@kms_chamelium_frames@hdmi-crc-argb8888
+igt@kms_chamelium_frames@hdmi-crc-bgr565
+igt@kms_chamelium_frames@hdmi-crc-bgr888
+igt@kms_chamelium_frames@hdmi-crc-fast
+igt@kms_chamelium_frames@hdmi-crc-rgb565
+igt@kms_chamelium_frames@hdmi-crc-rgb888
+igt@kms_chamelium_frames@hdmi-crc-xbgr8888
+igt@kms_chamelium_frames@hdmi-crc-xrgb1555
+igt@kms_chamelium_frames@hdmi-crc-xrgb8888
+igt@kms_chamelium_edid@hdmi-edid-read
+igt@kms_chamelium_hpd@hdmi-hpd
+igt@kms_chamelium_hpd@hdmi-hpd-fast
-- 
2.39.0.rc0.267.gcb52ba06e7-goog

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (9 preceding siblings ...)
  2022-12-06 19:51 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
@ 2022-12-06 23:45 ` Patchwork
  2022-12-07  0:14 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-06 23:45 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
URL   : https://patchwork.freedesktop.org/series/111501/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/756452 for the overview.

build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071502):
  FAILED: tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  cc -Itests/59830eb@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/libdrm/nouveau -I/usr/include/x86_64-linux-gnu -I/usr/include/valgrind -I/usr/include/alsa -I/usr/include -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wimplicit-fallthrough=0 -Wlogical-op -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-clobbered -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-pointer-arith -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread  -MD -MQ 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name ‘size_t’
   extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
                                                                  ^~~~~~
  /usr/include/xf86drmMode.h:520:64: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
  /usr/include/xf86drmMode.h:44:1:
  +#include <stddef.h>
   
  /usr/include/xf86drmMode.h:520:64:
   extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
                                                                  ^~~~~~
  ninja: build stopped: subcommand failed.
  section_end:1670369883:step_script
  section_start:1670369883:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369883:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071497):
  [4/329] Linking target tests/kms_frontbuffer_tracking.
  [5/329] Compiling C object 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o'.
  FAILED: tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  cc -Itests/59830eb@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/libdrm/nouveau -I/usr/include/valgrind -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wimplicit-fallthrough=0 -Wlogical-op -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-clobbered -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-pointer-arith -Wno-address-of-packed-member -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread -MD -MQ 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name ‘size_t’
    520 | extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
        |                                                                ^~~~~~
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:44:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
     43 | #include <drm.h>
    +++ |+#include <stddef.h>
     44 | 
  ninja: build stopped: subcommand failed.
  section_end:1670369910:step_script
  section_start:1670369910:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369912:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071501):
  ninja: build stopped: subcommand failed.
  ninja: Entering directory `build'
  [1/619] Generating version.h with a custom command.
  [2/331] Linking target lib/libi915_perf.so.1.5.
  [3/331] Generating symbol file 'lib/76b5a35@@i915_perf@sha/libi915_perf.so.1.5.symbols'.
  [4/331] Compiling C object 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o'.
  FAILED: tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  clang -Itests/59830eb@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/libdrm/nouveau -I/usr/include/valgrind -Xclang -fcolor-diagnostics -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-missing-field-initializers -Wno-pointer-arith -Wno-address-of-packed-member -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread -MD -MQ 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name 'size_t'
  extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
                                                                 ^
  1 error generated.
  ninja: build stopped: subcommand failed.
  section_end:1670369983:step_script
  section_start:1670369983:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369984:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071500):
  [4/235] Linking target tests/kms_frontbuffer_tracking.
  [5/235] Compiling C object 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o'.
  FAILED: tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  cc -Itests/59830eb@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I../lib/stubs/drm -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/valgrind -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wimplicit-fallthrough=0 -Wlogical-op -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-clobbered -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-pointer-arith -Wno-address-of-packed-member -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread -MD -MQ 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name ‘size_t’
    520 | extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
        |                                                                ^~~~~~
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:44:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
     43 | #include <drm.h>
    +++ |+#include <stddef.h>
     44 | 
  ninja: build stopped: subcommand failed.
  section_end:1670369891:step_script
  section_start:1670369891:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369892:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071498):
  [3/330] Generating symbol file 'lib/76b5a35@@i915_perf@sha/libi915_perf.so.1.5.symbols'.
  [4/330] Compiling C object 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o'.
  FAILED: tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  cc -Itests/59830eb@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I../lib/stubs/libunwind -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/libdrm/nouveau -I/usr/include/valgrind -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wimplicit-fallthrough=0 -Wlogical-op -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-clobbered -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-pointer-arith -Wno-address-of-packed-member -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread -MD -MQ 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/59830eb@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name ‘size_t’
    520 | extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
        |                                                                ^~~~~~
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:44:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
     43 | #include <drm.h>
    +++ |+#include <stddef.h>
     44 | 
  ninja: build stopped: subcommand failed.
  section_end:1670369910:step_script
  section_start:1670369910:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369912:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/33071499):
  [4/336] Linking target tests/kms_frontbuffer_tracking.
  [5/336] Compiling C object 'tests/tests@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o'.
  FAILED: tests/tests@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o 
  cc -Itests/tests@@kms_chamelium_edid@exe -Itests -I../tests -I../include/drm-uapi -I../include/linux-uapi -Ilib -I../lib -I../lib/stubs/syscalls -I. -I../ -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/libdrm/nouveau -I/usr/include/valgrind -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -std=gnu11 -O2 -g -D_GNU_SOURCE -include config.h -D_FORTIFY_SOURCE=2 -Wbad-function-cast -Wdeclaration-after-statement -Wformat=2 -Wimplicit-fallthrough=0 -Wlogical-op -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wuninitialized -Wunused -Wno-clobbered -Wno-maybe-uninitialized -Wno-missing-field-initializers -Wno-pointer-arith -Wno-address-of-packed-member -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-unused-result -Werror=address -Werror=array-bounds -Werror=implicit -Werror=init-self -Werror=int-to-pointer-cast -Werror=main -Werror=missing-braces -Werror=nonnull -Werror=pointer-to-int-cast -Werror=return-type -Werror=sequence-point -Werror=trigraphs -Werror=write-strings -fno-builtin-malloc -fno-builtin-calloc -fcommon -pthread  -MD -MQ 'tests/tests@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -MF 'tests/tests@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o.d' -o 'tests/tests@@kms_chamelium_edid@exe/chamelium_kms_chamelium_edid.c.o' -c ../tests/chamelium/kms_chamelium_edid.c
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:520:64: error: unknown type name ‘size_t’
    520 | extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size,
        |                                                                ^~~~~~
  In file included from ../tests/chamelium/kms_chamelium_edid.c:11:
  /usr/include/xf86drmMode.h:44:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
     43 | #include <drm.h>
    +++ |+#include <stddef.h>
     44 | 
  ninja: build stopped: subcommand failed.
  section_end:1670369893:step_script
  section_start:1670369893:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1670369894:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/756452

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (10 preceding siblings ...)
  2022-12-06 23:45 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4) Patchwork
@ 2022-12-07  0:14 ` Patchwork
  2022-12-07 12:59   ` Kamil Konieczny
  2022-12-08  6:29 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
  2022-12-08 15:58 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  13 siblings, 1 reply; 25+ messages in thread
From: Patchwork @ 2022-12-07  0:14 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 25837 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
URL   : https://patchwork.freedesktop.org/series/111501/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_8208 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_8208, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

Participating hosts (30 -> 44)
------------------------------

  Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
  Missing    (1): fi-cfl-8700k 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8208:

### IGT changes ###

#### Possible regressions ####

  * igt@i915_selftest@live@late_gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@late_gt_pm.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
    - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12475 and IGTPW_8208:

### New IGT tests (9) ###

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8208 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@debugfs_test@basic-hwmon:
    - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@debugfs_test@basic-hwmon.html

  * igt@gem_exec_gttfill@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
    - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@gem_exec_gttfill@basic.html

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
    - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@gem_mmap@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
    - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_mmap@basic.html

  * igt@gem_render_tiled_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_render_tiled_blits@basic.html

  * igt@gem_tiled_blits@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_blits@basic.html

  * igt@gem_tiled_fence_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html

  * igt@gem_tiled_pread_basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
    - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_tiled_pread_basic.html

  * igt@i915_module_load@load:
    - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i915_module_load@load.html

  * igt@i915_pm_backlight@basic-brightness:
    - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
    - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html

  * igt@i915_pm_rps@basic-api:
    - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
    - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
    - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_rps@basic-api.html

  * igt@i915_selftest@live@gt_heartbeat:
    - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html

  * igt@i915_selftest@live@gt_mocs:
    - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html

  * igt@i915_selftest@live@gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html

  * igt@kms_addfb_basic@basic-x-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html

  * igt@kms_addfb_basic@basic-y-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
    - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html

  * igt@kms_addfb_basic@tile-pitch-mismatch:
    - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
    - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
    - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
    - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
    - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html

  * igt@kms_force_connector_basic@force-load-detect:
    - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
    - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
    - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pipe_crc_basic@suspend-read-crc:
    - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html

  * igt@kms_psr@primary_page_flip:
    - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_psr@primary_page_flip.html

  * igt@kms_psr@sprite_plane_onoff:
    - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
    - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
    - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@prime_vgem@basic-fence-read:
    - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-fence-read.html

  * igt@prime_vgem@basic-gtt:
    - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
    - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-gtt.html

  * igt@prime_vgem@basic-userptr:
    - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
    - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
    - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-userptr.html

  * igt@prime_vgem@basic-write:
    - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
    - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-write.html

  * igt@runner@aborted:
    - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@runner@aborted.html

  
#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
  [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
  [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
  [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
  [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
  [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
  [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
  [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
  [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
  [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
  [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
  [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
  [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
  [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
  [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
  [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
  [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
  [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7084 -> IGTPW_8208

  CI-20190529: 20190529
  CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
  IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

[-- Attachment #2: Type: text/html, Size: 30678 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] [PATCH v4] Chamelium: Split kms_chamelium into multiple kms_chamelium tests
  2022-12-06 23:22     ` [igt-dev] [PATCH v4] " Mark Yacoub
@ 2022-12-07 11:39       ` Kamil Konieczny
  0 siblings, 0 replies; 25+ messages in thread
From: Kamil Konieczny @ 2022-12-07 11:39 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

On 2022-12-06 at 18:22:17 -0500, Mark Yacoub wrote:
> [Why]
> kms_chamelium tests file has grown so much and became a bit big to
> manage.
> Splitting specific tests like we do for kms_ tests into separate files
> puts logically related functionalities into the same place so tests are
> more clear.
> 
> [How]
> Split kms_chamelium into 4 different tests, each testing something
> specific. The tests are:
> 1. kms_chamelium_audio
> 2. kms_chamelium_edid
> 3. kms_chamelium_frames
> 4. kms_chamelium_hpd
> 5. kms_chamelium_color which used to be kms_color_chamelium but renamed
>    for consistency.
> 
> All common code lives in kms_chamelium_helper and the function names
> have a chamelium_ prefix.
> 

Please put here description of your changes, like:

v4:
  added missed includes
  moving assignment outside of assert

You can also put name where you address someones review, like
  added missed includes (Petri)

Look at other patch series with big version number for example
https://patchwork.freedesktop.org/series/105881/

While at it, look at descriptions of subtests, imho there you
need to add spaces at end/begin of multiline.

One more thing to consider is copyright, imho you should keep
original author in new files unless you added more (over 50%)
your own code. In case you added some your own code (non-trivial
changes) then you can add your copyright.

+cc Petri

Regards,
Kamil

> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> ---
>  docs/chamelium.txt                            |    2 +-
>  lib/igt_edid.h                                |    1 +
>  lib/igt_eld.h                                 |    1 +
>  lib/monitor_edids/monitor_edids_helper.c      |    2 +-
>  tests/chamelium/kms_chamelium.c               | 3132 -----------------
>  tests/chamelium/kms_chamelium_audio.c         |  858 +++++
>  ...olor_chamelium.c => kms_chamelium_color.c} |    0
>  tests/chamelium/kms_chamelium_edid.c          |  535 +++
>  tests/chamelium/kms_chamelium_frames.c        | 1085 ++++++
>  tests/chamelium/kms_chamelium_helper.c        |  330 ++
>  tests/chamelium/kms_chamelium_helper.h        |   74 +
>  tests/chamelium/kms_chamelium_hpd.c           |  512 +++
>  tests/intel-ci/blacklist.txt                  |    2 +-
>  tests/intel-ci/fast-feedback.testlist         |   18 +-
>  tests/kms_color_helper.h                      |    2 +-
>  tests/meson.build                             |   14 +-
>  tests/vc4_ci/vc4-chamelium-fast.testlist      |   28 +-
>  17 files changed, 3432 insertions(+), 3164 deletions(-)
>  delete mode 100644 tests/chamelium/kms_chamelium.c
>  create mode 100644 tests/chamelium/kms_chamelium_audio.c
>  rename tests/chamelium/{kms_color_chamelium.c => kms_chamelium_color.c} (100%)
>  create mode 100644 tests/chamelium/kms_chamelium_edid.c
>  create mode 100644 tests/chamelium/kms_chamelium_frames.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.c
>  create mode 100644 tests/chamelium/kms_chamelium_helper.h
>  create mode 100644 tests/chamelium/kms_chamelium_hpd.c
> 
> diff --git a/docs/chamelium.txt b/docs/chamelium.txt
> index c4c22468..f82c8b0c 100644
> --- a/docs/chamelium.txt
> +++ b/docs/chamelium.txt
> @@ -241,7 +241,7 @@ Current Support in IGT
>  
>  Support for the Chamelium platform in IGT is found in the following places:
>  * lib/igt_chamelium.c: library with Chamelium-related helpers
> -* tests/kms_chamelium.c: sub-tests using the Chamelium
> +* tests/kms_chamelium_*.c: sub-tests using the Chamelium
>  
>  As of early April 2019, the following features are tested by IGT:
>  * Pixel-by-pixel frame integrity tests for DP and HDMI
> diff --git a/lib/igt_edid.h b/lib/igt_edid.h
> index 477f16c2..85a9ef5e 100644
> --- a/lib/igt_edid.h
> +++ b/lib/igt_edid.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdint.h>
> +#include <stddef.h>
>  
>  #include <xf86drmMode.h>
>  
> diff --git a/lib/igt_eld.h b/lib/igt_eld.h
> index 30d7012d..1a46b6d2 100644
> --- a/lib/igt_eld.h
> +++ b/lib/igt_eld.h
> @@ -29,6 +29,7 @@
>  #include "config.h"
>  
>  #include <stdbool.h>
> +#include <stddef.h>
>  
>  #include "igt_edid.h"
>  
> diff --git a/lib/monitor_edids/monitor_edids_helper.c b/lib/monitor_edids/monitor_edids_helper.c
> index 41f199bd..1cbf1c22 100644
> --- a/lib/monitor_edids/monitor_edids_helper.c
> +++ b/lib/monitor_edids/monitor_edids_helper.c
> @@ -1,4 +1,4 @@
> -// SPDX-License-Identifier: GPL-2.0
> +// SPDX-License-Identifier: MIT
>  /*
>   * A helper library for parsing and making use of real EDID data from monitors
>   * and make them compatible with IGT and Chamelium.
> diff --git a/tests/chamelium/kms_chamelium.c b/tests/chamelium/kms_chamelium.c
> deleted file mode 100644
> index 3c4b4d75..00000000
> --- a/tests/chamelium/kms_chamelium.c
> +++ /dev/null
> @@ -1,3132 +0,0 @@
> -/*
> - * Copyright © 2016 Red Hat Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - * Authors:
> - *    Lyude Paul <lyude@redhat.com>
> - */
> -
> -#include "config.h"
> -#include "igt.h"
> -#include "igt_vc4.h"
> -#include "igt_edid.h"
> -#include "igt_eld.h"
> -#include "igt_infoframe.h"
> -#include "monitor_edids/dp_edids.h"
> -#include "monitor_edids/hdmi_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,
> -	TEST_MODESET_ON_OFF,
> -	TEST_MODESET_OFF,
> -};
> -
> -typedef struct {
> -	struct chamelium *chamelium;
> -	struct chamelium_port **ports;
> -	igt_display_t display;
> -	int port_count;
> -
> -	int drm_fd;
> -
> -	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> -} data_t;
> -
> -#define ONLINE_TIMEOUT 20 /* seconds */
> -
> -#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> -#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> -
> -#define HPD_TOGGLE_COUNT_VGA 5
> -#define HPD_TOGGLE_COUNT_DP_HDMI 15
> -#define HPD_TOGGLE_COUNT_FAST 3
> -
> -static void
> -get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
> -{
> -	drmModeConnector *connector;
> -	uint64_t link_status;
> -	drmModePropertyPtr prop;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		connector = chamelium_port_get_connector(data->chamelium,
> -							 data->ports[p], false);
> -
> -		igt_assert(kmstest_get_property(data->drm_fd,
> -						connector->connector_id,
> -						DRM_MODE_OBJECT_CONNECTOR,
> -						"link-status", NULL,
> -						&link_status, &prop));
> -
> -		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> -
> -		drmModeFreeProperty(prop);
> -		drmModeFreeConnector(connector);
> -	}
> -}
> -
> -/* Wait for hotplug and return the remaining time left from timeout */
> -static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> -{
> -	struct timespec start, end;
> -	int elapsed;
> -	bool detected;
> -
> -	igt_assert_eq(igt_gettime(&start), 0);
> -	detected = igt_hotplug_detected(mon, *timeout);
> -	igt_assert_eq(igt_gettime(&end), 0);
> -
> -	elapsed = igt_time_elapsed(&start, &end);
> -	igt_assert_lte(0, elapsed);
> -	*timeout = max(0, *timeout - elapsed);
> -
> -	return detected;
> -}
> -
> -static void
> -wait_for_connector_after_hotplug(data_t *data, struct udev_monitor *mon,
> -				 struct chamelium_port *port,
> -				 drmModeConnection status)
> -{
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int hotplug_count = 0;
> -
> -	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> -			  chamelium_port_get_name(port),
> -			  kmstest_connector_status_str(status));
> -
> -	while (timeout > 0) {
> -		if (!wait_for_hotplug(mon, &timeout))
> -			break;
> -
> -		hotplug_count++;
> -
> -		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> -						port) == status)
> -			return;
> -	}
> -
> -	igt_assert_f(false, "Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> -			    chamelium_port_get_name(port),
> -			    kmstest_connector_status_str(status),
> -			    kmstest_connector_status_str(chamelium_reprobe_connector(&data->display, data->chamelium, port)), hotplug_count);
> -}
> -
> -
> -static int chamelium_vga_modes[][2] = {
> -	{ 1600, 1200 },
> -	{ 1920, 1200 },
> -	{ 1920, 1080 },
> -	{ 1680, 1050 },
> -	{ 1280, 1024 },
> -	{ 1280, 960 },
> -	{ 1440, 900 },
> -	{ 1280, 800 },
> -	{ 1024, 768 },
> -	{ 1360, 768 },
> -	{ 1280, 720 },
> -	{ 800, 600 },
> -	{ 640, 480 },
> -	{ -1, -1 },
> -};
> -
> -static bool
> -prune_vga_mode(data_t *data, drmModeModeInfo *mode)
> -{
> -	int i = 0;
> -
> -	while (chamelium_vga_modes[i][0] != -1) {
> -		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> -		    mode->vdisplay == chamelium_vga_modes[i][1])
> -			return false;
> -
> -		i++;
> -	}
> -
> -	return true;
> -}
> -
> -static bool
> -check_analog_bridge(data_t *data, struct chamelium_port *port)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -	uint64_t edid_blob_id;
> -	const struct edid *edid;
> -	char edid_vendor[3];
> -
> -	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> -		drmModeFreeConnector(connector);
> -		return false;
> -	}
> -
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	edid = (const struct edid *) edid_blob->data;
> -	edid_get_mfg(edid, edid_vendor);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -
> -	/* Analog bridges provide their own EDID */
> -	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> -	    edid_vendor[2] != 'T')
> -		return true;
> -
> -	return false;
> -}
> -
> -static void chamelium_paint_xr24_pattern(uint32_t *data,
> -					 size_t width, size_t height,
> -					 size_t stride, size_t block_size)
> -{
> -	uint32_t colors[] = { 0xff000000,
> -			      0xffff0000,
> -			      0xff00ff00,
> -			      0xff0000ff,
> -			      0xffffffff };
> -	unsigned i, j;
> -
> -	for (i = 0; i < height; i++)
> -		for (j = 0; j < width; j++)
> -			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
> -}
> -
> -static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
> -				    uint32_t fourcc, size_t block_size,
> -				    struct igt_fb *fb)
> -{
> -	int fb_id;
> -	void *ptr;
> -
> -	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> -
> -	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> -			      DRM_FORMAT_MOD_LINEAR, fb);
> -	igt_assert(fb_id > 0);
> -
> -	ptr = igt_fb_map_buffer(fb->fd, fb);
> -	igt_assert(ptr);
> -
> -	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> -				     block_size);
> -	igt_fb_unmap_buffer(fb, ptr);
> -
> -	return fb_id;
> -}
> -
> -static void
> -enable_output(data_t *data,
> -	      struct chamelium_port *port,
> -	      igt_output_t *output,
> -	      drmModeModeInfo *mode,
> -	      struct igt_fb *fb)
> -{
> -	igt_display_t *display = output->display;
> -	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	drmModeConnector *connector = chamelium_port_get_connector(
> -	    data->chamelium, port, false);
> -
> -	igt_assert(primary);
> -
> -	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> -	igt_plane_set_fb(primary, fb);
> -	igt_output_override_mode(output, mode);
> -
> -	/* Clear any color correction values that might be enabled */
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
> -	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> -		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
> -
> -	igt_display_commit2(display, COMMIT_ATOMIC);
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> -		usleep(250000);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static enum pipe get_pipe_for_output(igt_display_t *display, igt_output_t *output)
> -{
> -	enum pipe pipe;
> -
> -	for_each_pipe(display, pipe) {
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			return pipe;
> -		}
> -	}
> -
> -	igt_assert_f(false, "No pipe found for output %s\n",
> -		     igt_output_name(output));
> -}
> -
> -static void create_fb_for_mode(data_t *data, struct igt_fb *fb, drmModeModeInfo *mode)
> -{
> -	int fb_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, fb);
> -
> -	igt_assert(fb_id > 0);
> -}
> -
> -static drmModeModeInfo get_mode_for_port(struct chamelium *chamelium,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector = chamelium_port_get_connector(chamelium,
> -								   port, false);
> -	drmModeModeInfo mode;
> -	igt_assert(&connector->modes[0] != NULL);
> -	memcpy(&mode, &connector->modes[0], sizeof(mode));
> -	drmModeFreeConnector(connector);
> -	return mode;
> -}
> -
> -static igt_output_t *get_output_for_port(data_t *data,
> -					 struct chamelium_port *port)
> -{
> -	drmModeConnector *connector =
> -		chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_output_t *output = igt_output_from_connector(&data->display,
> -							 connector);
> -	drmModeFreeConnector(connector);
> -	igt_assert(output != NULL);
> -	return output;
> -}
> -
> -static const char test_hotplug_for_each_pipe_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug for each pipe with valid output";
> -static void
> -test_hotplug_for_each_pipe(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	enum pipe pipe;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	chamelium_reset_state(&data->display,
> -			      data->chamelium,
> -			      port,
> -			      data->ports,
> -			      data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	/* Disconnect if any port got connected */
> -	chamelium_unplug(data->chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port,
> -			DRM_MODE_DISCONNECTED);
> -
> -	for_each_pipe(&data->display, pipe) {
> -		igt_flush_uevents(mon);
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -		output = get_output_for_port(data, port);
> -
> -		/* If pipe is valid for output then set it */
> -		if (igt_pipe_connector_valid(pipe, output)) {
> -			igt_output_set_pipe(output, pipe);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -
> -		chamelium_unplug(data->chamelium, port);
> -		wait_for_connector_after_hotplug(data, mon, port,
> -				DRM_MODE_DISCONNECTED);
> -		igt_flush_uevents(mon);
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_basic_hotplug_desc[] =
> -	"Check that we get uevents and updated connector status on "
> -	"hotplug and unplug";
> -static void
> -test_hotplug(data_t *data, struct chamelium_port *port, int toggle_count,
> -	     enum test_modeset_mode modeset_mode)
> -{
> -	int i;
> -	enum pipe pipe;
> -	struct igt_fb fb = {0};
> -	drmModeModeInfo mode;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	igt_output_t *output = get_output_for_port(data, port);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -
> -	for (i = 0; i < toggle_count; i++) {
> -		igt_flush_uevents(mon);
> -
> -		/* Check if we get a sysfs hotplug event */
> -		chamelium_plug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_CONNECTED);
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF ||
> -		    (modeset_mode == TEST_MODESET_ON && i == 0 )) {
> -			if (i == 0) {
> -				/* We can only get mode and pipe once we are connected */
> -				output = get_output_for_port(data, port);
> -				pipe = get_pipe_for_output(&data->display, output);
> -				mode = get_mode_for_port(data->chamelium, port);
> -				create_fb_for_mode(data, &fb, &mode);
> -			}
> -
> -			igt_output_set_pipe(output, pipe);
> -			enable_output(data, port, output, &mode, &fb);
> -		}
> -
> -		/* Now check if we get a hotplug from disconnection */
> -		chamelium_unplug(data->chamelium, port);
> -
> -		wait_for_connector_after_hotplug(data, mon, port,
> -						 DRM_MODE_DISCONNECTED);
> -
> -		igt_flush_uevents(mon);
> -
> -		if (modeset_mode == TEST_MODESET_ON_OFF) {
> -			igt_output_set_pipe(output, PIPE_NONE);
> -			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -		}
> -	}
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static void set_edid(data_t *data, struct chamelium_port *port,
> -		     enum igt_custom_edid_type edid)
> -{
> -	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> -}
> -
> -static const char igt_custom_edid_type_read_desc[] =
> -	"Make sure the EDID exposed by KMS is the same as the screen's";
> -static void
> -igt_custom_edid_type_read(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	drmModePropertyBlobPtr edid_blob = NULL;
> -	drmModeConnector *connector;
> -	size_t raw_edid_size;
> -	const struct edid *raw_edid;
> -	uint64_t edid_blob_id;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_skip_on(check_analog_bridge(data, port));
> -
> -	connector = chamelium_port_get_connector(data->chamelium, port, true);
> -	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> -					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> -					&edid_blob_id, NULL));
> -	igt_assert(edid_blob_id != 0);
> -	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
> -						      edid_blob_id));
> -
> -	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> -	raw_edid_size = edid_get_size(raw_edid);
> -	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> -
> -	drmModeFreePropertyBlob(edid_blob);
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void
> -try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -		       enum igt_suspend_state state, enum igt_suspend_test test,
> -		       struct udev_monitor *mon, bool connected)
> -{
> -	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> -						     DRM_MODE_CONNECTED;
> -	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> -	int delay;
> -	int p;
> -
> -	igt_flush_uevents(mon);
> -
> -	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> -
> -	if (port) {
> -		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> -					      !connected);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			port = data->ports[p];
> -			chamelium_schedule_hpd_toggle(data->chamelium, port,
> -						      delay, !connected);
> -		}
> -
> -		port = NULL;
> -	}
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(wait_for_hotplug(mon, &timeout));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	if (port) {
> -		igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -							  data->chamelium,
> -							  port),
> -							  target_state);
> -	} else {
> -		for (p = 0; p < data->port_count; p++) {
> -			drmModeConnection current_state;
> -
> -			port = data->ports[p];
> -			/*
> -			 * There could be as many hotplug events sent by
> -			 * driver as connectors we scheduled an HPD toggle on
> -			 * above, depending on timing. So if we're not seeing
> -			 * the expected connector state try to wait for an HPD
> -			 * event for each connector/port.
> -			 */
> -			current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			if (p > 0 && current_state != target_state) {
> -				igt_assert(wait_for_hotplug(mon, &timeout));
> -				current_state = chamelium_reprobe_connector(&data->display, data->chamelium, port);
> -			}
> -
> -			igt_assert_eq(current_state, target_state);
> -		}
> -
> -		port = NULL;
> -	}
> -}
> -
> -static const char test_suspend_resume_hpd_desc[] =
> -	"Toggle HPD during suspend, check that uevents are sent and connector "
> -	"status is updated";
> -static void
> -test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
> -			enum igt_suspend_state state,
> -			enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, port, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_hpd_common_desc[] =
> -	"Toggle HPD during suspend on all connectors, check that uevents are "
> -	"sent and connector status is updated";
> -static void
> -test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
> -			       enum igt_suspend_test test)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	struct chamelium_port *port;
> -	int p;
> -
> -	for (p = 0; p < data->port_count; p++) {
> -		port = data->ports[p];
> -		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium, NULL,
> -			      data->ports, data->port_count);
> -
> -	/* Make sure we notice new connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> -
> -	/* Now make sure we notice disconnected connectors after resuming */
> -	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_suspend_resume_edid_change_desc[] =
> -	"Simulate a screen being unplugged and another screen being plugged "
> -	"during suspend, check that a uevent is sent and connector status is "
> -	"updated";
> -static void
> -test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
> -				enum igt_suspend_state state,
> -				enum igt_suspend_test test,
> -				enum igt_custom_edid_type edid,
> -				enum igt_custom_edid_type alt_edid)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	bool link_status_failed[2][data->port_count];
> -	int p;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Catch the event and flush all remaining ones. */
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_flush_uevents(mon);
> -
> -	/* First plug in the port */
> -	set_edid(data, port, edid);
> -	chamelium_plug(data->chamelium, port);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	/*
> -	 * Change the edid before we suspend. On resume, the machine should
> -	 * notice the EDID change and fire a hotplug event.
> -	 */
> -	set_edid(data, port, alt_edid);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[0]);
> -
> -	igt_flush_uevents(mon);
> -
> -	igt_system_suspend_autoresume(state, test);
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> -
> -	get_connectors_link_status_failed(data, link_status_failed[1]);
> -
> -	for (p = 0; p < data->port_count; p++)
> -		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
> -}
> -
> -static igt_output_t *
> -prepare_output(data_t *data, struct chamelium_port *port, enum igt_custom_edid_type edid)
> -{
> -	igt_display_t *display = &data->display;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	/* The chamelium's default EDID has a lot of resolutions, way more then
> -	 * we need to test. Additionally the default EDID doesn't support HDMI
> -	 * audio.
> -	 */
> -	set_edid(data, port, edid);
> -
> -	chamelium_plug(data->chamelium, port);
> -	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> -					      port, DRM_MODE_CONNECTED);
> -
> -	igt_display_reset(display);
> -
> -	output = get_output_for_port(data, port);
> -
> -	/* Refresh pipe to update connected status */
> -	igt_output_set_pipe(output, PIPE_NONE);
> -
> -	pipe = get_pipe_for_output(display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	return output;
> -}
> -
> -static void do_test_display(data_t *data, struct chamelium_port *port,
> -			    igt_output_t *output, drmModeModeInfo *mode,
> -			    uint32_t fourcc, enum chamelium_check check,
> -			    int count)
> -{
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	struct igt_fb frame_fb, fb;
> -	int i, fb_id, captured_frame_count;
> -	int frame_id;
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
> -				  DRM_FORMAT_MOD_LINEAR);
> -	igt_assert(frame_id > 0);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&fb);
> -
> -	enable_output(data, port, output, mode, &frame_fb);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		igt_crc_t *expected_crc;
> -		igt_crc_t *crc;
> -
> -		/* We want to keep the display running for a little bit, since
> -		 * there's always the potential the driver isn't able to keep
> -		 * the display running properly for very long
> -		 */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == count);
> -
> -		igt_debug("Captured %d frames\n", captured_frame_count);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		for (i = 0; i < captured_frame_count; i++)
> -			chamelium_assert_crc_eq_or_dump(data->chamelium,
> -							expected_crc, &crc[i],
> -							&fb, i);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> -		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		igt_assert(count == 1);
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG)
> -			chamelium_crop_analog_frame(dump, mode->hdisplay,
> -						    mode->vdisplay);
> -
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	igt_remove_fb(data->drm_fd, &frame_fb);
> -	igt_remove_fb(data->drm_fd, &fb);
> -}
> -
> -static const char test_display_one_mode_desc[] =
> -	"Pick the first mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_one_mode(data_t *data, struct chamelium_port *port,
> -				  uint32_t fourcc, enum chamelium_check check,
> -				  int count)
> -{
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	igt_require(igt_plane_has_format_mod(primary, fourcc, DRM_FORMAT_MOD_LINEAR));
> -
> -	mode = &connector->modes[0];
> -	if (check == CHAMELIUM_CHECK_ANALOG) {
> -		bool bridge = check_analog_bridge(data, port);
> -
> -		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> -	}
> -
> -	do_test_display(data, port, output, mode, fourcc, check, count);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static const char test_display_all_modes_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then check captured frames are correct";
> -static void test_display_all_modes(data_t *data, struct chamelium_port *port,
> -				   uint32_t fourcc, enum chamelium_check check,
> -				   int count)
> -{
> -	bool bridge;
> -	int i, count_modes;
> -
> -	if (check == CHAMELIUM_CHECK_ANALOG)
> -		bridge = check_analog_bridge(data, port);
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -		igt_require(igt_plane_has_format_mod(primary, fourcc,
> -			    DRM_FORMAT_MOD_LINEAR));
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> -		    prune_vga_mode(data, mode))
> -			continue;
> -
> -		do_test_display(data, port, output, mode, fourcc, check,
> -				count);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -static const char test_display_frame_dump_desc[] =
> -	"For each mode of the IGT base EDID, display and capture a few "
> -	"frames, then download the captured frames and compare them "
> -	"bit-by-bit to the sent ones";
> -static void
> -test_display_frame_dump(data_t *data, struct chamelium_port *port)
> -{
> -
> -	int i, count_modes;
> -
> -	i = 0;
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		struct igt_fb fb;
> -		struct chamelium_frame_dump *frame;
> -		drmModeModeInfo *mode;
> -		drmModeConnector *connector;
> -		int fb_id, j;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port,
> -							 false);
> -		primary = igt_output_get_plane_type(output,
> -						    DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		igt_debug("Reading frame dumps from Chamelium...\n");
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> -		for (j = 0; j < 5; j++) {
> -			frame = chamelium_read_captured_frame(data->chamelium,
> -							      j);
> -			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> -			chamelium_destroy_frame_dump(frame);
> -		}
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> -
> -static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> -		       drmModeModeInfo *mode)
> -{
> -	struct chamelium_video_params video_params = {0};
> -	double mode_clock;
> -	int mode_hsync_offset, mode_vsync_offset;
> -	int mode_hsync_width, mode_vsync_width;
> -	int mode_hsync_polarity, mode_vsync_polarity;
> -
> -	chamelium_port_get_video_params(chamelium, port, &video_params);
> -
> -	mode_clock = (double) mode->clock / 1000;
> -
> -	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> -		/* this is what chamelium understands as offsets for DP */
> -		mode_hsync_offset = mode->htotal - mode->hsync_start;
> -		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> -	} else {
> -		/* and this is what they are for other connectors */
> -		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> -		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> -	}
> -
> -	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> -	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> -
> -	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> -	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> -
> -	igt_debug("Checking video mode:\n");
> -	igt_debug("clock: got %f, expected %f ± %f%%\n",
> -		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
> -	igt_debug("hactive: got %d, expected %d\n",
> -		  video_params.hactive, mode->hdisplay);
> -	igt_debug("vactive: got %d, expected %d\n",
> -		  video_params.vactive, mode->vdisplay);
> -	igt_debug("hsync_offset: got %d, expected %d\n",
> -		  video_params.hsync_offset, mode_hsync_offset);
> -	igt_debug("vsync_offset: got %d, expected %d\n",
> -		  video_params.vsync_offset, mode_vsync_offset);
> -	igt_debug("htotal: got %d, expected %d\n",
> -		  video_params.htotal, mode->htotal);
> -	igt_debug("vtotal: got %d, expected %d\n",
> -		  video_params.vtotal, mode->vtotal);
> -	igt_debug("hsync_width: got %d, expected %d\n",
> -		  video_params.hsync_width, mode_hsync_width);
> -	igt_debug("vsync_width: got %d, expected %d\n",
> -		  video_params.vsync_width, mode_vsync_width);
> -	igt_debug("hsync_polarity: got %d, expected %d\n",
> -		  video_params.hsync_polarity, mode_hsync_polarity);
> -	igt_debug("vsync_polarity: got %d, expected %d\n",
> -		  video_params.vsync_polarity, mode_vsync_polarity);
> -
> -	if (!isnan(video_params.clock)) {
> -		igt_assert(video_params.clock >
> -			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> -		igt_assert(video_params.clock <
> -			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> -	}
> -	igt_assert(video_params.hactive == mode->hdisplay);
> -	igt_assert(video_params.vactive == mode->vdisplay);
> -	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> -	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> -	igt_assert(video_params.htotal == mode->htotal);
> -	igt_assert(video_params.vtotal == mode->vtotal);
> -	igt_assert(video_params.hsync_width == mode_hsync_width);
> -	igt_assert(video_params.vsync_width == mode_vsync_width);
> -	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> -	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> -}
> -
> -static const char test_mode_timings_desc[] =
> -	"For each mode of the IGT base EDID, perform a modeset and check the "
> -	"mode detected by the Chamelium receiver matches the mode we set";
> -static void test_mode_timings(data_t *data, struct chamelium_port *port)
> -{
> -	int i, count_modes;
> -
> -	i = 0;
> -	igt_require(chamelium_supports_get_video_params(data->chamelium));
> -	do {
> -		igt_output_t *output;
> -		igt_plane_t *primary;
> -		drmModeConnector *connector;
> -		drmModeModeInfo *mode;
> -		int fb_id;
> -		struct igt_fb fb;
> -
> -		/*
> -		 * let's reset state each mode so we will get the
> -		 * HPD pulses realibably
> -		 */
> -		igt_modeset_disable_all_outputs(&data->display);
> -		chamelium_reset_state(&data->display, data->chamelium,
> -				      port, data->ports, data->port_count);
> -
> -		/*
> -		 * modes may change due to mode pruining and link issues, so we
> -		 * need to refresh the connector
> -		 */
> -		output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -		connector = chamelium_port_get_connector(data->chamelium, port, false);
> -		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -		igt_assert(primary);
> -
> -		/* we may skip some modes due to above but that's ok */
> -		count_modes = connector->count_modes;
> -		if (i >= count_modes)
> -			break;
> -
> -		mode = &connector->modes[i];
> -
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay, mode->vdisplay,
> -						    DRM_FORMAT_XRGB8888,
> -						    DRM_FORMAT_MOD_LINEAR,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		/* Trigger the FSM */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> -
> -		check_mode(data->chamelium, port, mode);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -		drmModeFreeConnector(connector);
> -	} while (++i < count_modes);
> -}
> -
> -struct vic_mode {
> -	int hactive, vactive;
> -	int vrefresh; /* Hz */
> -	uint32_t picture_ar;
> -};
> -
> -/* Maps Video Identification Codes to a mode */
> -static const struct vic_mode vic_modes[] = {
> -	[16] = {
> -		.hactive = 1920,
> -		.vactive = 1080,
> -		.vrefresh = 60,
> -		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> -	},
> -};
> -
> -/* Maps aspect ratios to their mode flag */
> -static const uint32_t mode_ar_flags[] = {
> -	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> -};
> -
> -static enum infoframe_avi_picture_aspect_ratio
> -get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> -{
> -	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> -	switch (aspect_ratio) {
> -	case DRM_MODE_PICTURE_ASPECT_4_3:
> -		return INFOFRAME_AVI_PIC_AR_4_3;
> -	case DRM_MODE_PICTURE_ASPECT_16_9:
> -		return INFOFRAME_AVI_PIC_AR_16_9;
> -	default:
> -		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> -	}
> -}
> -
> -static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> -				 drmModeModeInfo *drm_mode)
> -{
> -	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> -
> -	return vic_mode->hactive == drm_mode->hdisplay &&
> -	       vic_mode->vactive == drm_mode->vdisplay &&
> -	       vic_mode->vrefresh == drm_mode->vrefresh &&
> -	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> -}
> -
> -static const char test_display_aspect_ratio_desc[] =
> -	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> -	"check they include the relevant fields";
> -static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	drmModeConnector *connector;
> -	drmModeModeInfo *mode;
> -	int fb_id, i;
> -	struct igt_fb fb;
> -	bool found, ok;
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_avi infoframe_avi;
> -	uint8_t vic = 16; /* TODO: test more VICs */
> -	const struct vic_mode *vic_mode;
> -	uint32_t aspect_ratio;
> -	enum infoframe_avi_picture_aspect_ratio frame_ar;
> -
> -	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_ASPECT_RATIO);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	vic_mode = &vic_modes[vic];
> -	aspect_ratio = vic_mode->picture_ar;
> -
> -	found = false;
> -	igt_assert(connector->count_modes > 0);
> -	for (i = 0; i < connector->count_modes; i++) {
> -		mode = &connector->modes[i];
> -
> -		if (vic_mode_matches_drm(vic_mode, mode)) {
> -			found = true;
> -			break;
> -		}
> -	}
> -	igt_assert_f(found,
> -		     "Failed to find mode with the correct aspect ratio\n");
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> -						 CHAMELIUM_INFOFRAME_AVI);
> -	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> -
> -	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> -				 infoframe->payload, infoframe->payload_size);
> -	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> -
> -	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> -
> -	igt_debug("Checking AVI InfoFrame\n");
> -	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> -		  infoframe_avi.picture_aspect_ratio, frame_ar);
> -	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> -		  infoframe_avi.vic, vic);
> -
> -	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> -	igt_assert(infoframe_avi.vic == vic);
> -
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_remove_fb(data->drm_fd, &fb);
> -	drmModeFreeConnector(connector);
> -}
> -
> -
> -/* Playback parameters control the audio signal we synthesize and send */
> -#define PLAYBACK_CHANNELS 2
> -#define PLAYBACK_SAMPLES 1024
> -
> -/* Capture paremeters control the audio signal we receive */
> -#define CAPTURE_SAMPLES 2048
> -
> -#define AUDIO_TIMEOUT 2000 /* ms */
> -/* A streak of 3 gives confidence that the signal is good. */
> -#define MIN_STREAK 3
> -
> -#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> -#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> -#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> -
> -/* TODO: enable >48KHz rates, these are not reliable */
> -static int test_sampling_rates[] = {
> -	32000,
> -	44100,
> -	48000,
> -	/* 88200, */
> -	/* 96000, */
> -	/* 176400, */
> -	/* 192000, */
> -};
> -
> -static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
> -
> -/* Test frequencies (Hz): a sine signal will be generated for each.
> - *
> - * Depending on the sampling rate chosen, it might not be possible to properly
> - * detect the generated sine (see Nyquist–Shannon sampling theorem).
> - * Frequencies that can't be reliably detected will be automatically pruned in
> - * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> - * tested with a 192KHz sampling rate.
> - */
> -static int test_frequencies[] = {
> -	300,
> -	600,
> -	1200,
> -	10000,
> -	80000,
> -};
> -
> -static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> -
> -static const snd_pcm_format_t test_formats[] = {
> -	SND_PCM_FORMAT_S16_LE,
> -	SND_PCM_FORMAT_S24_LE,
> -	SND_PCM_FORMAT_S32_LE,
> -};
> -
> -static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
> -
> -struct audio_state {
> -	struct alsa *alsa;
> -	struct chamelium *chamelium;
> -	struct chamelium_port *port;
> -	struct chamelium_stream *stream;
> -
> -	/* The capture format is only available after capture has started. */
> -	struct {
> -		snd_pcm_format_t format;
> -		int channels;
> -		int rate;
> -	} playback, capture;
> -
> -	char *name;
> -	struct audio_signal *signal; /* for frequencies test only */
> -	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	size_t recv_pages;
> -	int msec;
> -
> -	int dump_fd;
> -	char *dump_path;
> -
> -	pthread_t thread;
> -	atomic_bool run;
> -	atomic_bool positive; /* for pulse test only */
> -};
> -
> -static void audio_state_init(struct audio_state *state, data_t *data,
> -			     struct alsa *alsa, struct chamelium_port *port,
> -			     snd_pcm_format_t format, int channels, int rate)
> -{
> -	memset(state, 0, sizeof(*state));
> -	state->dump_fd = -1;
> -
> -	state->alsa = alsa;
> -	state->chamelium = data->chamelium;
> -	state->port = port;
> -
> -	state->playback.format = format;
> -	state->playback.channels = channels;
> -	state->playback.rate = rate;
> -
> -	alsa_configure_output(alsa, format, channels, rate);
> -
> -	state->stream = chamelium_stream_init();
> -	igt_assert_f(state->stream,
> -		     "Failed to initialize Chamelium stream client\n");
> -}
> -
> -static void audio_state_fini(struct audio_state *state)
> -{
> -	chamelium_stream_deinit(state->stream);
> -	free(state->name);
> -}
> -
> -static void *run_audio_thread(void *data)
> -{
> -	struct alsa *alsa = data;
> -
> -	alsa_run(alsa, -1);
> -	return NULL;
> -}
> -
> -static void audio_state_start(struct audio_state *state, const char *name)
> -{
> -	int ret;
> -	bool ok;
> -	size_t i, j;
> -	enum chamelium_stream_realtime_mode stream_mode;
> -	char dump_suffix[64];
> -
> -	free(state->name);
> -	state->name = strdup(name);
> -	state->recv_pages = 0;
> -	state->msec = 0;
> -
> -	igt_debug("Starting %s test with playback format %s, "
> -		  "sampling rate %d Hz and %d channels\n",
> -		  name, snd_pcm_format_name(state->playback.format),
> -		  state->playback.rate, state->playback.channels);
> -
> -	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> -
> -	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> -	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> -	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> -
> -	/* Start playing audio */
> -	state->run = true;
> -	ret = pthread_create(&state->thread, NULL,
> -			     run_audio_thread, state->alsa);
> -	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> -
> -	/* The Chamelium device only supports this PCM format. */
> -	state->capture.format = SND_PCM_FORMAT_S32_LE;
> -
> -	/* Only after we've started playing audio, we can retrieve the capture
> -	 * format used by the Chamelium device. */
> -	chamelium_get_audio_format(state->chamelium, state->port,
> -				   &state->capture.rate,
> -				   &state->capture.channels);
> -	if (state->capture.rate == 0) {
> -		igt_debug("Audio receiver doesn't indicate the capture "
> -			 "sampling rate, assuming it's %d Hz\n",
> -			 state->playback.rate);
> -		state->capture.rate = state->playback.rate;
> -	}
> -
> -	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> -					    state->channel_mapping);
> -	/* Make sure we can capture all channels we send. */
> -	for (i = 0; i < state->playback.channels; i++) {
> -		ok = false;
> -		for (j = 0; j < state->capture.channels; j++) {
> -			if (state->channel_mapping[j] == i) {
> -				ok = true;
> -				break;
> -			}
> -		}
> -		igt_assert_f(ok, "Cannot capture all channels\n");
> -	}
> -
> -	if (igt_frame_dump_is_enabled()) {
> -		snprintf(dump_suffix, sizeof(dump_suffix),
> -			 "capture-%s-%s-%dch-%dHz",
> -			 name, snd_pcm_format_name(state->playback.format),
> -			 state->playback.channels, state->playback.rate);
> -
> -		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> -							      state->capture.rate,
> -							      state->capture.channels,
> -							      &state->dump_path);
> -		igt_assert_f(state->dump_fd >= 0,
> -			     "Failed to create audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_receive(struct audio_state *state,
> -				int32_t **recv, size_t *recv_len)
> -{
> -	bool ok;
> -	size_t page_count;
> -	size_t recv_size;
> -
> -	ok = chamelium_stream_receive_realtime_audio(state->stream,
> -						     &page_count,
> -						     recv, recv_len);
> -	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> -
> -	state->msec = state->recv_pages * *recv_len
> -		      / (double) state->capture.channels
> -		      / (double) state->capture.rate * 1000;
> -	state->recv_pages++;
> -
> -	if (state->dump_fd >= 0) {
> -		recv_size = *recv_len * sizeof(int32_t);
> -		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
> -			     "Failed to write to audio dump file\n");
> -	}
> -}
> -
> -static void audio_state_stop(struct audio_state *state, bool success)
> -{
> -	bool ok;
> -	int ret;
> -	struct chamelium_audio_file *audio_file;
> -	enum igt_log_level log_level;
> -
> -	igt_debug("Stopping audio playback\n");
> -	state->run = false;
> -	ret = pthread_join(state->thread, NULL);
> -	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> -
> -	ok = chamelium_stream_stop_realtime_audio(state->stream);
> -	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> -
> -	audio_file = chamelium_stop_capturing_audio(state->chamelium,
> -						    state->port);
> -	if (audio_file) {
> -		igt_debug("Audio file saved on the Chamelium in %s\n",
> -			  audio_file->path);
> -		chamelium_destroy_audio_file(audio_file);
> -	}
> -
> -	if (state->dump_fd >= 0) {
> -		close(state->dump_fd);
> -		state->dump_fd = -1;
> -
> -		if (success) {
> -			/* Test succeeded, no need to keep the captured data */
> -			unlink(state->dump_path);
> -		} else
> -			igt_debug("Saved captured audio data to %s\n",
> -				  state->dump_path);
> -		free(state->dump_path);
> -		state->dump_path = NULL;
> -	}
> -
> -	if (success)
> -		log_level = IGT_LOG_DEBUG;
> -	else
> -		log_level = IGT_LOG_CRITICAL;
> -
> -	igt_log(IGT_LOG_DOMAIN, log_level, "Audio %s test result for format %s, "
> -		"sampling rate %d Hz and %d channels: %s\n",
> -		state->name, snd_pcm_format_name(state->playback.format),
> -		state->playback.rate, state->playback.channels,
> -		success ? "ALL GREEN" : "FAILED");
> -
> -}
> -
> -static void check_audio_infoframe(struct audio_state *state)
> -{
> -	struct chamelium_infoframe *infoframe;
> -	struct infoframe_audio infoframe_audio;
> -	struct infoframe_audio expected = {0};
> -	bool ok;
> -
> -	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "Chamelium board doesn't support GetLastInfoFrame\n");
> -		return;
> -	}
> -
> -	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> -	expected.channel_count = state->playback.channels;
> -	expected.sampling_freq = state->playback.rate;
> -	expected.sample_size = snd_pcm_format_width(state->playback.format);
> -
> -	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> -						 CHAMELIUM_INFOFRAME_AUDIO);
> -	if (infoframe == NULL && state->playback.channels <= 2) {
> -		/* Audio InfoFrames are optional for mono and stereo audio */
> -		igt_debug("Skipping audio InfoFrame check: "
> -			  "no InfoFrame received\n");
> -		return;
> -	}
> -	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> -
> -	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> -				   infoframe->payload, infoframe->payload_size);
> -	chamelium_infoframe_destroy(infoframe);
> -	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> -
> -	igt_debug("Checking audio InfoFrame:\n");
> -	igt_debug("coding_type: got %d, expected %d\n",
> -		  infoframe_audio.coding_type, expected.coding_type);
> -	igt_debug("channel_count: got %d, expected %d\n",
> -		  infoframe_audio.channel_count, expected.channel_count);
> -	igt_debug("sampling_freq: got %d, expected %d\n",
> -		  infoframe_audio.sampling_freq, expected.sampling_freq);
> -	igt_debug("sample_size: got %d, expected %d\n",
> -		  infoframe_audio.sample_size, expected.sample_size);
> -
> -	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> -		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> -	if (infoframe_audio.channel_count >= 0)
> -		igt_assert(infoframe_audio.channel_count == expected.channel_count);
> -	if (infoframe_audio.sampling_freq >= 0)
> -		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
> -	if (infoframe_audio.sample_size >= 0)
> -		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> -}
> -
> -static int
> -audio_output_frequencies_callback(void *data, void *buffer, int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	audio_signal_fill(state->signal, tmp, samples);
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool test_audio_frequencies(struct audio_state *state)
> -{
> -	int freq, step;
> -	int32_t *recv, *buf;
> -	double *channel;
> -	size_t i, j, streak;
> -	size_t recv_len, buf_len, buf_cap, channel_len;
> -	bool success;
> -	int capture_chan;
> -
> -	state->signal = audio_signal_init(state->playback.channels,
> -					  state->playback.rate);
> -	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> -
> -	/* We'll choose different frequencies per channel to make sure they are
> -	 * independent from each other. To do so, we'll add a different offset
> -	 * to the base frequencies for each channel. We need to choose a big
> -	 * enough offset so that we're sure to detect mixed up channels. We
> -	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> -	 * difference.
> -	 *
> -	 * Note that we assume capture_rate == playback_rate. We'll assert this
> -	 * later on. We cannot retrieve the capture rate before starting
> -	 * playing audio, so we don't really have the choice.
> -	 */
> -	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> -	for (i = 0; i < test_frequencies_count; i++) {
> -		for (j = 0; j < state->playback.channels; j++) {
> -			freq = test_frequencies[i] + j * step;
> -			audio_signal_add_frequency(state->signal, freq, j);
> -		}
> -	}
> -	audio_signal_synthesize(state->signal);
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_frequencies_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	audio_state_start(state, "frequencies");
> -
> -	igt_assert_f(state->capture.rate == state->playback.rate,
> -		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> -		     state->capture.rate, state->playback.rate);
> -
> -	/* Needs to be a multiple of 128, because that's the number of samples
> -	 * we get per channel each time we receive an audio page from the
> -	 * Chamelium device.
> -	 *
> -	 * Additionally, this value needs to be high enough to guarantee we
> -	 * capture a full period of each sine we generate. If we capture 2048
> -	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> -	 * sines. For lower sampling rates, the capture duration will be
> -	 * longer.
> -	 */
> -	channel_len = CAPTURE_SAMPLES;
> -	channel = malloc(sizeof(double) * channel_len);
> -
> -	buf_cap = state->capture.channels * channel_len;
> -	buf = malloc(sizeof(int32_t) * buf_cap);
> -	buf_len = 0;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -
> -	success = false;
> -	streak = 0;
> -	while (!success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> -		buf_len += recv_len;
> -
> -		if (buf_len < buf_cap)
> -			continue;
> -		igt_assert(buf_len == buf_cap);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (j = 0; j < state->playback.channels; j++) {
> -			capture_chan = state->channel_mapping[j];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", j, capture_chan);
> -
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     buf, buf_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			if (audio_signal_detect(state->signal,
> -						state->capture.rate, j,
> -						channel, channel_len))
> -				streak++;
> -			else
> -				streak = 0;
> -		}
> -
> -		buf_len = 0;
> -
> -		success = streak == MIN_STREAK * state->playback.channels;
> -	}
> -
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -	free(buf);
> -	free(channel);
> -	audio_signal_fini(state->signal);
> -
> -	check_audio_infoframe(state);
> -
> -	return success;
> -}
> -
> -static int audio_output_flatline_callback(void *data, void *buffer,
> -					     int samples)
> -{
> -	struct audio_state *state = data;
> -	double *tmp;
> -	size_t len, i;
> -
> -	len = samples * state->playback.channels;
> -	tmp = malloc(len * sizeof(double));
> -	for (i = 0; i < len; i++)
> -		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	audio_convert_to(buffer, tmp, len, state->playback.format);
> -	free(tmp);
> -
> -	return state->run ? 0 : -1;
> -}
> -
> -static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> -{
> -	double expected, min, max;
> -	size_t i;
> -	bool ok;
> -
> -	min = max = NAN;
> -	for (i = 0; i < buf_len; i++) {
> -		if (isnan(min) || buf[i] < min)
> -			min = buf[i];
> -		if (isnan(max) || buf[i] > max)
> -			max = buf[i];
> -	}
> -
> -	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> -	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> -	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> -	if (ok)
> -		igt_debug("Flatline wave amplitude detected\n");
> -	else
> -		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> -			  min, max);
> -	return ok;
> -}
> -
> -static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> -{
> -	size_t i;
> -
> -	for (i = 0; i < buf_len; i++) {
> -		if (buf[i] < 0)
> -			return i;
> -	}
> -
> -	return -1;
> -}
> -
> -/** test_audio_flatline:
> - *
> - * Send a constant value (one positive, then a negative one) and check that:
> - *
> - * - The amplitude of the flatline is correct
> - * - All channels switch from a positive signal to a negative one at the same
> - *   time (ie. all channels are aligned)
> - */
> -static bool test_audio_flatline(struct audio_state *state)
> -{
> -	bool success, amp_success, align_success;
> -	int32_t *recv;
> -	size_t recv_len, i, channel_len;
> -	ssize_t j;
> -	int streak, capture_chan;
> -	double *channel;
> -	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> -
> -	alsa_register_output_callback(state->alsa,
> -				      audio_output_flatline_callback, state,
> -				      PLAYBACK_SAMPLES);
> -
> -	/* Start by sending a positive signal */
> -	state->positive = true;
> -
> -	audio_state_start(state, "flatline");
> -
> -	for (i = 0; i < state->playback.channels; i++)
> -		falling_edges[i] = -1;
> -
> -	recv = NULL;
> -	recv_len = 0;
> -	amp_success = false;
> -	streak = 0;
> -	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> -		audio_state_receive(state, &recv, &recv_len);
> -
> -		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> -
> -		for (i = 0; i < state->playback.channels; i++) {
> -			capture_chan = state->channel_mapping[i];
> -			igt_assert(capture_chan >= 0);
> -			igt_debug("Processing channel %zu (captured as "
> -				  "channel %d)\n", i, capture_chan);
> -
> -			channel_len = audio_extract_channel_s32_le(NULL, 0,
> -								   recv, recv_len,
> -								   state->capture.channels,
> -								   capture_chan);
> -			channel = malloc(channel_len * sizeof(double));
> -			audio_extract_channel_s32_le(channel, channel_len,
> -						     recv, recv_len,
> -						     state->capture.channels,
> -						     capture_chan);
> -
> -			/* Check whether the amplitude is fine */
> -			if (detect_flatline_amplitude(channel, channel_len,
> -						      state->positive))
> -				streak++;
> -			else
> -				streak = 0;
> -
> -			/* If we're now sending a negative signal, detect the
> -			 * falling edge */
> -			j = detect_falling_edge(channel, channel_len);
> -			if (!state->positive && j >= 0) {
> -				falling_edges[i] = recv_len * state->recv_pages
> -						   + j;
> -			}
> -
> -			free(channel);
> -		}
> -
> -		amp_success = streak == MIN_STREAK * state->playback.channels;
> -
> -		if (amp_success && state->positive) {
> -			/* Switch to a negative signal after we've detected the
> -			 * positive one. */
> -			state->positive = false;
> -			amp_success = false;
> -			streak = 0;
> -			igt_debug("Switching to negative square wave\n");
> -		}
> -	}
> -
> -	/* Check alignment between all channels by comparing the index of the
> -	 * falling edge. */
> -	align_success = true;
> -	for (i = 0; i < state->playback.channels; i++) {
> -		if (falling_edges[i] < 0) {
> -			igt_critical("Falling edge not detected for channel %zu\n",
> -				     i);
> -			align_success = false;
> -			continue;
> -		}
> -
> -		if (abs(falling_edges[0] - falling_edges[i]) >
> -		    FLATLINE_ALIGN_ACCURACY) {
> -			igt_critical("Channel alignment mismatch: "
> -				     "channel 0 has a falling edge at index %d "
> -				     "while channel %zu has index %d\n",
> -				     falling_edges[0], i, falling_edges[i]);
> -			align_success = false;
> -		}
> -	}
> -
> -	success = amp_success && align_success;
> -	audio_state_stop(state, success);
> -
> -	free(recv);
> -
> -	return success;
> -}
> -
> -static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
> -				      int channels, int sampling_rate)
> -{
> -	if (!alsa_test_output_configuration(alsa, format, channels,
> -					    sampling_rate)) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because at least one of the "
> -			  "selected output devices doesn't support this "
> -			  "configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	/* TODO: the Chamelium device sends a malformed signal for some audio
> -	 * configurations. See crbug.com/950917 */
> -	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> -			channels > 2) {
> -		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> -			  "and %d channels because the Chamelium device "
> -			  "doesn't support this configuration\n",
> -			  snd_pcm_format_name(format),
> -			  sampling_rate, channels);
> -		return false;
> -	}
> -	return true;
> -}
> -
> -static const char test_display_audio_desc[] =
> -	"Playback various audio signals with various audio formats/rates, "
> -	"capture them and check they are correct";
> -static void
> -test_display_audio(data_t *data, struct chamelium_port *port,
> -		   const char *audio_device, enum igt_custom_edid_type edid)
> -{
> -	bool run, success;
> -	struct alsa *alsa;
> -	int ret;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id, i, j;
> -	int channels, sampling_rate;
> -	snd_pcm_format_t format;
> -	struct audio_state state;
> -
> -	igt_require(alsa_has_exclusive_access());
> -
> -	/* Old Chamelium devices need an update for DisplayPort audio and
> -	 * chamelium_get_audio_format support. */
> -	igt_require(chamelium_has_audio_support(data->chamelium, port));
> -
> -	alsa = alsa_init();
> -	igt_assert(alsa);
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because the receiver won't try to receive audio if
> -	 * it doesn't receive video. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	run = false;
> -	success = true;
> -	for (i = 0; i < test_sampling_rates_count; i++) {
> -		for (j = 0; j < test_formats_count; j++) {
> -			ret = alsa_open_output(alsa, audio_device);
> -			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> -
> -			/* TODO: playback on all 8 available channels (this
> -			 * isn't supported by Chamelium devices yet, see
> -			 * https://crbug.com/950917) */
> -			format = test_formats[j];
> -			channels = PLAYBACK_CHANNELS;
> -			sampling_rate = test_sampling_rates[i];
> -
> -			if (!check_audio_configuration(alsa, format, channels,
> -						       sampling_rate))
> -				continue;
> -
> -			run = true;
> -
> -			audio_state_init(&state, data, alsa, port,
> -					 format, channels, sampling_rate);
> -			success &= test_audio_frequencies(&state);
> -			success &= test_audio_flatline(&state);
> -			audio_state_fini(&state);
> -
> -			alsa_close_output(alsa);
> -		}
> -	}
> -
> -	/* Make sure we tested at least one frequency and format. */
> -	igt_assert(run);
> -	/* Make sure all runs were successful. */
> -	igt_assert(success);
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -
> -	free(alsa);
> -}
> -
> -static const char test_display_audio_edid_desc[] =
> -	"Plug a connector with an EDID suitable for audio, check ALSA's "
> -	"EDID-Like Data reports the correct audio parameters";
> -static void
> -test_display_audio_edid(data_t *data, struct chamelium_port *port,
> -			enum igt_custom_edid_type edid)
> -{
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id;
> -	struct eld_entry eld;
> -	struct eld_sad *sad;
> -
> -	igt_require(eld_is_supported());
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	output = prepare_output(data, port, edid);
> -	connector = chamelium_port_get_connector(data->chamelium, port, false);
> -	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	/* Enable the output because audio cannot be played on inactive
> -	 * connectors. */
> -	igt_assert(connector->count_modes > 0);
> -	mode = &connector->modes[0];
> -
> -	fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -					    mode->hdisplay, mode->vdisplay,
> -					    DRM_FORMAT_XRGB8888,
> -					    DRM_FORMAT_MOD_LINEAR,
> -					    0, 0, 0, &fb);
> -	igt_assert(fb_id > 0);
> -
> -	enable_output(data, port, output, mode, &fb);
> -
> -	igt_assert(eld_get_igt(&eld));
> -	igt_assert(eld.sads_len == 1);
> -
> -	sad = &eld.sads[0];
> -	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> -	igt_assert(sad->channels == 2);
> -	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
> -		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
> -	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
> -		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
> -
> -	igt_remove_fb(data->drm_fd, &fb);
> -
> -	drmModeFreeConnector(connector);
> -}
> -
> -static void randomize_plane_stride(data_t *data,
> -				   uint32_t width, uint32_t height,
> -				   uint32_t format, uint64_t modifier,
> -				   size_t *stride)
> -{
> -	size_t stride_min;
> -	uint32_t max_tile_w = 4, tile_w, tile_h;
> -	int i;
> -	struct igt_fb dummy;
> -
> -	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> -
> -	/* Randomize the stride to less than twice the minimum. */
> -	*stride = (rand() % stride_min) + stride_min;
> -
> -	/*
> -	 * Create a dummy FB to determine bpp for each plane, and calculate
> -	 * the maximum tile width from that.
> -	 */
> -	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> -	for (i = 0; i < dummy.num_planes; i++) {
> -		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
> -
> -		if (tile_w > max_tile_w)
> -			max_tile_w = tile_w;
> -	}
> -	igt_remove_fb(data->drm_fd, &dummy);
> -
> -	/*
> -	 * Pixman requires the stride to be aligned to 32-bits, which is
> -	 * reflected in the initial value of max_tile_w and the hw
> -	 * may require a multiple of tile width, choose biggest of the 2.
> -	 */
> -	*stride = ALIGN(*stride, max_tile_w);
> -}
> -
> -static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> -				  uint32_t height, uint32_t format,
> -				  uint64_t *modifier)
> -{
> -	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> -		/* Randomize the column height to less than twice the minimum. */
> -		size_t column_height = (rand() % height) + height;
> -
> -		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
> -			  column_height);
> -
> -		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
> -	}
> -}
> -
> -static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
> -				  drmModeModeInfo *mode,
> -				  uint32_t *width, uint32_t *height,
> -				  uint32_t *format, uint64_t *modifier,
> -				  bool allow_yuv)
> -{
> -	int min_dim;
> -	uint32_t idx[plane->format_mod_count];
> -	unsigned int count = 0;
> -	unsigned int i;
> -
> -	/* First pass to count the supported formats. */
> -	for (i = 0; i < plane->format_mod_count; i++)
> -		if (igt_fb_supported_format(plane->formats[i]) &&
> -		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> -			idx[count++] = i;
> -
> -	igt_assert(count > 0);
> -
> -	i = idx[rand() % count];
> -	*format = plane->formats[i];
> -	*modifier = plane->modifiers[i];
> -
> -	update_tiled_modifier(plane, *width, *height, *format, modifier);
> -
> -	/*
> -	 * Randomize width and height in the mode dimensions range.
> -	 *
> -	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> -	 * least min_dim, because src_w = width - (rand % w / 2).
> -	 *
> -	 * Use a minimum dimension of 16 for YUV, because planar YUV
> -	 * subsamples the UV plane.
> -	 */
> -	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> -
> -	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> -	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> -}
> -
> -static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> -			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> -			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> -			    struct igt_fb *fb)
> -{
> -	igt_plane_set_fb(plane, fb);
> -
> -	igt_plane_set_position(plane, crtc_x, crtc_y);
> -	igt_plane_set_size(plane, crtc_w, crtc_h);
> -
> -	igt_fb_set_position(fb, plane, src_x, src_y);
> -	igt_fb_set_size(fb, plane, src_w, src_h);
> -}
> -
> -static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
> -					drmModeModeInfo *mode,
> -					struct igt_fb *fb,
> -					uint32_t *src_w, uint32_t *src_h,
> -					uint32_t *src_x, uint32_t *src_y,
> -					uint32_t *crtc_w, uint32_t *crtc_h,
> -					int32_t *crtc_x, int32_t *crtc_y,
> -					bool allow_scaling)
> -{
> -	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> -	uint32_t width = fb->width, height = fb->height;
> -	double ratio;
> -	int ret;
> -
> -	/* Randomize source offset in the first half of the original size. */
> -	*src_x = rand() % (width / 2);
> -	*src_y = rand() % (height / 2);
> -
> -	/* The source size only includes the active source area. */
> -	*src_w = width - *src_x;
> -	*src_h = height - *src_y;
> -
> -	if (allow_scaling) {
> -		*crtc_w = (rand() % mode->hdisplay) + 1;
> -		*crtc_h = (rand() % mode->vdisplay) + 1;
> -
> -		/*
> -		 * Don't bother with scaling if dimensions are quite close in
> -		 * order to get non-scaling cases more frequently. Also limit
> -		 * scaling to 3x to avoid agressive filtering that makes
> -		 * comparison less reliable, and don't go above 2x downsampling
> -		 * to avoid possible hw limitations.
> -		 */
> -
> -		ratio = ((double) *crtc_w / *src_w);
> -		if (ratio < 0.5)
> -			*src_w = *crtc_w * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_w = *src_w;
> -		else if (ratio > 3.0)
> -			*crtc_w = *src_w * 3;
> -
> -		ratio = ((double) *crtc_h / *src_h);
> -		if (ratio < 0.5)
> -			*src_h = *crtc_h * 2;
> -		else if (ratio > 0.8 && ratio < 1.2)
> -			*crtc_h = *src_h;
> -		else if (ratio > 3.0)
> -			*crtc_h = *src_h * 3;
> -	} else {
> -		*crtc_w = *src_w;
> -		*crtc_h = *src_h;
> -	}
> -
> -	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> -		/*
> -		 * When scaling is involved, make sure to not go off-bounds or
> -		 * scaled clipping may result in decimal dimensions, that most
> -		 * drivers don't support.
> -		 */
> -		if (*crtc_w < mode->hdisplay)
> -			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> -		else
> -			*crtc_x = 0;
> -
> -		if (*crtc_h < mode->vdisplay)
> -			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> -		else
> -			*crtc_y = 0;
> -	} else {
> -		/*
> -		 * Randomize the on-crtc position and allow the plane to go
> -		 * off-display by less than half of its on-crtc dimensions.
> -		 */
> -		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> -		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> -	}
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
> -			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
> -	ret = igt_display_try_commit_atomic(&data->display,
> -					    DRM_MODE_ATOMIC_TEST_ONLY |
> -					    DRM_MODE_ATOMIC_ALLOW_MODESET,
> -					    NULL);
> -	if (!ret)
> -		return;
> -
> -	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
> -	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
> -
> -	/* Make YUV coordinates a multiple of 2 and retry the math. */
> -	if (is_yuv) {
> -		*src_x &= ~1;
> -		*src_y &= ~1;
> -		*src_w &= ~1;
> -		*src_h &= ~1;
> -		/* To handle 1:1 scaling, clear crtc_w/h too. */
> -		*crtc_w &= ~1;
> -		*crtc_h &= ~1;
> -
> -		if (*crtc_x < 0 && (*crtc_x & 1))
> -			(*crtc_x)++;
> -		else
> -			*crtc_x &= ~1;
> -
> -		/* If negative, round up to 0 instead of down */
> -		if (*crtc_y < 0 && (*crtc_y & 1))
> -			(*crtc_y)++;
> -		else
> -			*crtc_y &= ~1;
> -
> -		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -				*crtc_h, *crtc_x, *crtc_y, fb);
> -		ret = igt_display_try_commit_atomic(&data->display,
> -						DRM_MODE_ATOMIC_TEST_ONLY |
> -						DRM_MODE_ATOMIC_ALLOW_MODESET,
> -						NULL);
> -		if (!ret)
> -			return;
> -	}
> -
> -	igt_assert(!ret || allow_scaling);
> -	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> -		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
> -
> -	*crtc_w = *src_w;
> -	*crtc_h = *src_h;
> -
> -	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> -			*crtc_h, *crtc_x, *crtc_y, fb);
> -	igt_display_commit_atomic(&data->display,
> -				  DRM_MODE_ATOMIC_TEST_ONLY |
> -				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> -}
> -
> -static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
> -			     uint32_t src_w, uint32_t src_h,
> -			     uint32_t src_x, uint32_t src_y,
> -			     uint32_t crtc_w, uint32_t crtc_h,
> -			     int32_t crtc_x, int32_t crtc_y,
> -			     struct igt_fb *fb)
> -{
> -	cairo_surface_t *surface;
> -	cairo_surface_t *clipped_surface;
> -	cairo_t *cr;
> -
> -	surface = igt_get_cairo_surface(data->drm_fd, fb);
> -
> -	if (src_x || src_y) {
> -		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> -							     src_w, src_h);
> -
> -		cr = cairo_create(clipped_surface);
> -
> -		cairo_translate(cr, -1. * src_x, -1. * src_y);
> -
> -		cairo_set_source_surface(cr, surface, 0, 0);
> -
> -		cairo_paint(cr);
> -		cairo_surface_flush(clipped_surface);
> -
> -		cairo_destroy(cr);
> -	} else {
> -		clipped_surface = surface;
> -	}
> -
> -	cr = cairo_create(result);
> -
> -	cairo_translate(cr, crtc_x, crtc_y);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_scale(cr, (double) crtc_w / src_w,
> -			    (double) crtc_h / src_h);
> -	}
> -
> -	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> -	cairo_surface_destroy(clipped_surface);
> -
> -	if (src_w != crtc_w || src_h != crtc_h) {
> -		cairo_pattern_set_filter(cairo_get_source(cr),
> -					 CAIRO_FILTER_BILINEAR);
> -		cairo_pattern_set_extend(cairo_get_source(cr),
> -					 CAIRO_EXTEND_NONE);
> -	}
> -
> -	cairo_paint(cr);
> -	cairo_surface_flush(result);
> -
> -	cairo_destroy(cr);
> -}
> -
> -static void prepare_randomized_plane(data_t *data,
> -				     drmModeModeInfo *mode,
> -				     igt_plane_t *plane,
> -				     struct igt_fb *overlay_fb,
> -				     unsigned int index,
> -				     cairo_surface_t *result_surface,
> -				     bool allow_scaling, bool allow_yuv)
> -{
> -	struct igt_fb pattern_fb;
> -	uint32_t overlay_fb_w, overlay_fb_h;
> -	uint32_t overlay_src_w, overlay_src_h;
> -	uint32_t overlay_src_x, overlay_src_y;
> -	int32_t overlay_crtc_x, overlay_crtc_y;
> -	uint32_t overlay_crtc_w, overlay_crtc_h;
> -	uint32_t format;
> -	uint64_t modifier;
> -	size_t stride;
> -	bool tiled;
> -	int fb_id;
> -
> -	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> -			      &format, &modifier, allow_yuv);
> -
> -	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> -	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
> -		  index, overlay_fb_w, overlay_fb_h,
> -		  igt_format_str(format), tiled ? "tiled" : "linear");
> -
> -	/* Get a pattern framebuffer for the overlay plane. */
> -	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> -					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
> -			       format, modifier, &stride);
> -
> -	igt_debug("Plane %d: stride %ld\n", index, stride);
> -
> -	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> -					   modifier, stride);
> -	igt_assert(fb_id > 0);
> -
> -	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> -				    &overlay_src_w, &overlay_src_h,
> -				    &overlay_src_x, &overlay_src_y,
> -				    &overlay_crtc_w, &overlay_crtc_h,
> -				    &overlay_crtc_x, &overlay_crtc_y,
> -				    allow_scaling);
> -
> -	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
> -		  overlay_src_w, overlay_src_h);
> -	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> -		  overlay_src_x, overlay_src_y);
> -	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
> -		  overlay_crtc_w, overlay_crtc_h);
> -	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
> -		  overlay_crtc_x, overlay_crtc_y);
> -
> -	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> -			 overlay_src_x, overlay_src_y,
> -			 overlay_crtc_w, overlay_crtc_h,
> -			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
> -
> -	/* Remove the original pattern framebuffer. */
> -	igt_remove_fb(data->drm_fd, &pattern_fb);
> -}
> -
> -static const char test_display_planes_random_desc[] =
> -	"Setup a few overlay planes with random parameters, capture the frame "
> -	"and check it matches the expected output";
> -static void test_display_planes_random(data_t *data,
> -				       struct chamelium_port *port,
> -				       enum chamelium_check check)
> -{
> -	igt_output_t *output;
> -	drmModeModeInfo *mode;
> -	igt_plane_t *primary_plane;
> -	struct igt_fb primary_fb;
> -	struct igt_fb result_fb;
> -	struct igt_fb *overlay_fbs;
> -	igt_crc_t *crc;
> -	igt_crc_t *expected_crc;
> -	struct chamelium_fb_crc_async_data *fb_crc;
> -	unsigned int overlay_planes_max = 0;
> -	unsigned int overlay_planes_count;
> -	cairo_surface_t *result_surface;
> -	int captured_frame_count;
> -	bool allow_scaling;
> -	bool allow_yuv;
> -	unsigned int i;
> -	unsigned int fb_id;
> -
> -	switch (check) {
> -	case CHAMELIUM_CHECK_CRC:
> -		allow_scaling = false;
> -		allow_yuv = false;
> -		break;
> -	case CHAMELIUM_CHECK_CHECKERBOARD:
> -		allow_scaling = true;
> -		allow_yuv = true;
> -		break;
> -	default:
> -		igt_assert(false);
> -	}
> -
> -	srand(time(NULL));
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	/* Find the connector and pipe. */
> -	output = prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> -
> -	mode = igt_output_get_mode(output);
> -
> -	/* Get a framebuffer for the primary plane. */
> -	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary_plane);
> -
> -	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> -					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> -	igt_assert(fb_id > 0);
> -
> -	/* Get a framebuffer for the cairo composition result. */
> -	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
> -			      mode->vdisplay, DRM_FORMAT_XRGB8888,
> -			      DRM_FORMAT_MOD_LINEAR, &result_fb);
> -	igt_assert(fb_id > 0);
> -
> -	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> -
> -	/* Paint the primary framebuffer on the result surface. */
> -	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> -			 &primary_fb);
> -
> -	/* Configure the primary plane. */
> -	igt_plane_set_fb(primary_plane, &primary_fb);
> -
> -	overlay_planes_max =
> -		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> -
> -	/* Limit the number of planes to a reasonable scene. */
> -	overlay_planes_max = min(overlay_planes_max, 4u);
> -
> -	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> -	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> -
> -	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> -
> -	for (i = 0; i < overlay_planes_count; i++) {
> -		struct igt_fb *overlay_fb = &overlay_fbs[i];
> -		igt_plane_t *plane =
> -			igt_output_get_plane_type_index(output,
> -							DRM_PLANE_TYPE_OVERLAY,
> -							i);
> -		igt_assert(plane);
> -
> -		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> -					 result_surface, allow_scaling,
> -					 allow_yuv);
> -	}
> -
> -	cairo_surface_destroy(result_surface);
> -
> -	if (check == CHAMELIUM_CHECK_CRC)
> -		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> -								&result_fb);
> -
> -	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> -
> -	if (check == CHAMELIUM_CHECK_CRC) {
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_count);
> -
> -		igt_assert(captured_frame_count == 1);
> -
> -		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> -
> -		chamelium_assert_crc_eq_or_dump(data->chamelium,
> -						expected_crc, crc,
> -						&result_fb, 0);
> -
> -		free(expected_crc);
> -		free(crc);
> -	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> -		struct chamelium_frame_dump *dump;
> -
> -		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> -						  0, 0);
> -		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> -						     dump, &result_fb, check);
> -		chamelium_destroy_frame_dump(dump);
> -	}
> -
> -	for (i = 0; i < overlay_planes_count; i++)
> -		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> -
> -	free(overlay_fbs);
> -
> -	igt_remove_fb(data->drm_fd, &primary_fb);
> -	igt_remove_fb(data->drm_fd, &result_fb);
> -}
> -
> -static const char test_hpd_without_ddc_desc[] =
> -	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> -static void
> -test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> -{
> -	struct udev_monitor *mon = igt_watch_uevents();
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -	igt_flush_uevents(mon);
> -
> -	/* Disable the DDC on the connector and make sure we still get a
> -	 * hotplug
> -	 */
> -	chamelium_port_set_ddc_state(data->chamelium, port, false);
> -	chamelium_plug(data->chamelium, port);
> -
> -	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> -	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> -						  data->chamelium, port),
> -						  DRM_MODE_CONNECTED);
> -
> -	igt_cleanup_uevents(mon);
> -}
> -
> -static const char test_hpd_storm_detect_desc[] =
> -	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> -	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> -	"storm";
> -static void
> -test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
> -{
> -	struct udev_monitor *mon;
> -	int count = 0;
> -
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> -
> -	mon = igt_watch_uevents();
> -	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> -
> -	/*
> -	 * Polling should have been enabled by the HPD storm at this point,
> -	 * so we should only get at most 1 hotplug event
> -	 */
> -	igt_until_timeout(5)
> -		count += igt_hotplug_detected(mon, 1);
> -	igt_assert_lt(count, 2);
> -
> -	igt_cleanup_uevents(mon);
> -	igt_hpd_storm_reset(data->drm_fd);
> -}
> -
> -static const char test_hpd_storm_disable_desc[] =
> -	"Disable HPD storm detection, trigger a storm and check the kernel "
> -	"doesn't detect one";
> -static void
> -test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
> -{
> -	igt_require_hpd_storm_ctl(data->drm_fd);
> -	igt_modeset_disable_all_outputs(&data->display);
> -	chamelium_reset_state(&data->display, data->chamelium,
> -			      port, data->ports, data->port_count);
> -
> -	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> -	chamelium_fire_hpd_pulses(data->chamelium, port,
> -				  width, 10);
> -	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> -
> -	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,
> -				   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;
> -
> -		monitor_edid *edid = &edids_list[i];
> -		igt_info("Testing out the EDID for %s\n",
> -			 monitor_edid_get_name(edid));
> -
> -		/* Getting and Setting the EDID on Chamelium. */
> -		chamelium_edid =
> -			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> -}
> -
> -static const char igt_edid_resolution_list_desc[] =
> -	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> -	" screen resolution matches the mode resolution.";
> -
> -static void edid_resolution_list(data_t *data, struct chamelium_port *port)
> -{
> -	struct chamelium *chamelium = data->chamelium;
> -	struct udev_monitor *mon = igt_watch_uevents();
> -	drmModeConnector *connector;
> -	drmModeModeInfoPtr modes;
> -	int count_modes;
> -	int i;
> -	igt_output_t *output;
> -	enum pipe pipe;
> -
> -	chamelium_unplug(chamelium, port);
> -	set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> -
> -	igt_flush_uevents(mon);
> -	chamelium_plug(chamelium, port);
> -	wait_for_connector_after_hotplug(data, mon, port, DRM_MODE_CONNECTED);
> -	igt_flush_uevents(mon);
> -
> -	connector = chamelium_port_get_connector(chamelium, port, true);
> -	modes = connector->modes;
> -	count_modes = connector->count_modes;
> -
> -	output = get_output_for_port(data, port);
> -	pipe = get_pipe_for_output(&data->display, output);
> -	igt_output_set_pipe(output, pipe);
> -
> -	for (i = 0; i < count_modes; ++i)
> -		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> -
> -	for (i = 0; i < count_modes; ++i) {
> -		struct igt_fb fb = { 0 };
> -		bool is_video_stable;
> -		int screen_res_w, screen_res_h;
> -
> -		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> -			 modes[i].vrefresh);
> -
> -		/* Set the screen mode with the one we chose. */
> -		create_fb_for_mode(data, &fb, &modes[i]);
> -		enable_output(data, port, output, &modes[i], &fb);
> -		is_video_stable = chamelium_port_wait_video_input_stable(
> -			chamelium, port, 10);
> -		igt_assert(is_video_stable);
> -
> -		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> -					      &screen_res_h);
> -		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> -		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> -
> -		igt_remove_fb(data->drm_fd, &fb);
> -	}
> -
> -	igt_modeset_disable_all_outputs(&data->display);
> -	drmModeFreeConnector(connector);
> -}
> -
> -#define for_each_port(p, port)            \
> -	for (p = 0, port = data.ports[p]; \
> -	     p < data.port_count;         \
> -	     p++, port = data.ports[p])
> -
> -#define connector_subtest(name__, type__)                    \
> -	igt_subtest(name__)                                  \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -#define connector_dynamic_subtest(name__, type__)            \
> -	igt_subtest_with_dynamic(name__)                     \
> -		for_each_port(p, port)                       \
> -			if (chamelium_port_get_type(port) == \
> -			    DRM_MODE_CONNECTOR_ ## type__)
> -
> -
> -static data_t data;
> -
> -IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> -igt_main
> -{
> -	struct chamelium_port *port;
> -	int p;
> -	size_t i;
> -
> -	igt_fixture {
> -		/* So fbcon doesn't try to reprobe things itself */
> -		kmstest_set_vt_graphics_mode();
> -
> -		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
> -		igt_display_require(&data.display, data.drm_fd);
> -		igt_require(data.display.is_atomic);
> -
> -		/*
> -		 * XXX: disabling modeset, can be removed when
> -		 * igt_display_require will start doing this for us
> -		 */
> -		igt_display_commit2(&data.display, COMMIT_ATOMIC);
> -
> -		/* we need to initalize chamelium after igt_display_require */
> -		data.chamelium = chamelium_init(data.drm_fd, &data.display);
> -		igt_require(data.chamelium);
> -
> -		data.ports = chamelium_get_ports(data.chamelium,
> -						 &data.port_count);
> -
> -		for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> -			data.edids[i] = chamelium_new_edid(data.chamelium,
> -							   igt_kms_get_custom_edid(i));
> -		}
> -	}
> -
> -	igt_describe("DisplayPort tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-fast", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("dp-edid-read", DisplayPort) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> -					       ARRAY_SIZE(DP_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("dp-edid-stress-resolution-non-4k",
> -				  DisplayPort)
> -			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> -					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> -
> -		igt_describe(igt_edid_resolution_list_desc);
> -		connector_subtest("dp-edid-resolution-list", DisplayPort)
> -			edid_resolution_list(&data, port);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("dp-hpd-storm", DisplayPort)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_DP);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-single", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("dp-crc-fast", DisplayPort)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("dp-crc-multiple", DisplayPort)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("dp-frame-dump", DisplayPort)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("dp-mode-timings", DisplayPort)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("dp-audio", DisplayPort)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("dp-audio-edid", DisplayPort)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_DP_AUDIO);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("HDMI tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_HDMIA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_DP_HDMI,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-fast", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("hdmi-edid-read", HDMIA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_4K));
> -
> -		igt_describe(igt_edid_stress_resolution_desc);
> -		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> -			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> -					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_storm_detect_desc);
> -		connector_subtest("hdmi-hpd-storm", HDMIA)
> -			test_hpd_storm_detect(&data, port,
> -					      HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_hpd_storm_disable_desc);
> -		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> -			test_hpd_storm_disable(&data, port,
> -					       HPD_STORM_PULSE_INTERVAL_HDMI);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_MEM,
> -							SUSPEND_TEST_NONE,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_suspend_resume_edid_change_desc);
> -		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> -			test_suspend_resume_edid_change(&data, port,
> -							SUSPEND_STATE_DISK,
> -							SUSPEND_TEST_DEVICES,
> -							IGT_CUSTOM_EDID_BASE,
> -							IGT_CUSTOM_EDID_ALT);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-single", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_subtest("hdmi-crc-fast", HDMIA)
> -			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> -					      CHAMELIUM_CHECK_CRC, 1);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("hdmi-crc-multiple", HDMIA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_CRC, 3);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CRC, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-crc-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CRC);
> -
> -		igt_describe(test_display_one_mode_desc);
> -		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA) {
> -			int k;
> -			igt_output_t *output;
> -			igt_plane_t *primary;
> -
> -			output = prepare_output(&data, port, IGT_CUSTOM_EDID_BASE);
> -			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> -			igt_assert(primary);
> -
> -			for (k = 0; k < primary->format_mod_count; k++) {
> -				if (!igt_fb_supported_format(primary->formats[k]))
> -					continue;
> -
> -				if (!igt_format_is_yuv(primary->formats[k]))
> -					continue;
> -
> -				if (primary->modifiers[k] != DRM_FORMAT_MOD_LINEAR)
> -					continue;
> -
> -				igt_dynamic_f("%s", igt_format_str(primary->formats[k]))
> -					test_display_one_mode(&data, port, primary->formats[k],
> -							      CHAMELIUM_CHECK_CHECKERBOARD, 1);
> -			}
> -		}
> -
> -		igt_describe(test_display_planes_random_desc);
> -		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> -			test_display_planes_random(&data, port,
> -						   CHAMELIUM_CHECK_CHECKERBOARD);
> -
> -		igt_describe(test_display_frame_dump_desc);
> -		connector_subtest("hdmi-frame-dump", HDMIA)
> -			test_display_frame_dump(&data, port);
> -
> -		igt_describe(test_mode_timings_desc);
> -		connector_subtest("hdmi-mode-timings", HDMIA)
> -			test_mode_timings(&data, port);
> -
> -		igt_describe(test_display_audio_desc);
> -		connector_subtest("hdmi-audio", HDMIA)
> -			test_display_audio(&data, port, "HDMI",
> -					   IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_audio_edid_desc);
> -		connector_subtest("hdmi-audio-edid", HDMIA)
> -			test_display_audio_edid(&data, port,
> -						IGT_CUSTOM_EDID_HDMI_AUDIO);
> -
> -		igt_describe(test_display_aspect_ratio_desc);
> -		connector_subtest("hdmi-aspect-ratio", HDMIA)
> -			test_display_aspect_ratio(&data, port);
> -
> -		igt_describe(test_hotplug_for_each_pipe_desc);
> -		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> -			test_hotplug_for_each_pipe(&data, port);
> -	}
> -
> -	igt_describe("VGA tests");
> -	igt_subtest_group {
> -		igt_fixture {
> -			chamelium_require_connector_present(data.ports, DRM_MODE_CONNECTOR_VGA,
> -							    data.port_count, 1);
> -		}
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-fast", VGA)
> -			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON_OFF);
> -
> -		igt_describe(test_basic_hotplug_desc);
> -		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> -			test_hotplug(&data, port,
> -				     HPD_TOGGLE_COUNT_FAST,
> -				     TEST_MODESET_ON);
> -
> -		igt_describe(igt_custom_edid_type_read_desc);
> -		connector_subtest("vga-edid-read", VGA) {
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_BASE);
> -			igt_custom_edid_type_read(&data, port, IGT_CUSTOM_EDID_ALT);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-suspend", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_MEM,
> -						SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_desc);
> -		connector_subtest("vga-hpd-after-hibernate", VGA)
> -			test_suspend_resume_hpd(&data, port,
> -						SUSPEND_STATE_DISK,
> -						SUSPEND_TEST_DEVICES);
> -
> -		igt_describe(test_hpd_without_ddc_desc);
> -		connector_subtest("vga-hpd-without-ddc", VGA)
> -			test_hpd_without_ddc(&data, port);
> -
> -		igt_describe(test_display_all_modes_desc);
> -		connector_subtest("vga-frame-dump", VGA)
> -			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> -					       CHAMELIUM_CHECK_ANALOG, 1);
> -	}
> -
> -	igt_describe("Tests that operate on all connectors");
> -	igt_subtest_group {
> -
> -		igt_fixture {
> -			igt_require(data.port_count);
> -		}
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-suspend")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_MEM,
> -						       SUSPEND_TEST_NONE);
> -
> -		igt_describe(test_suspend_resume_hpd_common_desc);
> -		igt_subtest("common-hpd-after-hibernate")
> -			test_suspend_resume_hpd_common(&data,
> -						       SUSPEND_STATE_DISK,
> -						       SUSPEND_TEST_DEVICES);
> -	}
> -
> -	igt_describe(test_hotplug_for_each_pipe_desc);
> -	connector_subtest("vga-hpd-for-each-pipe", VGA)
> -		test_hotplug_for_each_pipe(&data, port);
> -
> -	igt_fixture {
> -		igt_display_fini(&data.display);
> -		close(data.drm_fd);
> -	}
> -}
> diff --git a/tests/chamelium/kms_chamelium_audio.c b/tests/chamelium/kms_chamelium_audio.c
> new file mode 100644
> index 00000000..4d13744c
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_audio.c
> @@ -0,0 +1,858 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the Audio functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +/* Playback parameters control the audio signal we synthesize and send */
> +#define PLAYBACK_CHANNELS 2
> +#define PLAYBACK_SAMPLES 1024
> +
> +/* Capture paremeters control the audio signal we receive */
> +#define CAPTURE_SAMPLES 2048
> +
> +#define AUDIO_TIMEOUT 2000 /* ms */
> +/* A streak of 3 gives confidence that the signal is good. */
> +#define MIN_STREAK 3
> +
> +#define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
> +#define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
> +#define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
> +
> +struct audio_state {
> +	struct alsa *alsa;
> +	struct chamelium *chamelium;
> +	struct chamelium_port *port;
> +	struct chamelium_stream *stream;
> +
> +	/* The capture format is only available after capture has started. */
> +	struct {
> +		snd_pcm_format_t format;
> +		int channels;
> +		int rate;
> +	} playback, capture;
> +
> +	char *name;
> +	struct audio_signal *signal; /* for frequencies test only */
> +	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	size_t recv_pages;
> +	int msec;
> +
> +	int dump_fd;
> +	char *dump_path;
> +
> +	pthread_t thread;
> +	atomic_bool run;
> +	atomic_bool positive; /* for pulse test only */
> +};
> +
> +/* TODO: enable >48KHz rates, these are not reliable */
> +static int test_sampling_rates[] = {
> +	32000, 44100, 48000,
> +	/* 88200, */
> +	/* 96000, */
> +	/* 176400, */
> +	/* 192000, */
> +};
> +
> +static int test_sampling_rates_count =
> +	sizeof(test_sampling_rates) / sizeof(int);
> +
> +/* Test frequencies (Hz): a sine signal will be generated for each.
> + *
> + * Depending on the sampling rate chosen, it might not be possible to properly
> + * detect the generated sine (see Nyquist–Shannon sampling theorem).
> + * Frequencies that can't be reliably detected will be automatically pruned in
> + * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
> + * tested with a 192KHz sampling rate.
> + */
> +static int test_frequencies[] = {
> +	300, 600, 1200, 10000, 80000,
> +};
> +
> +static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
> +
> +static const snd_pcm_format_t test_formats[] = {
> +	SND_PCM_FORMAT_S16_LE,
> +	SND_PCM_FORMAT_S24_LE,
> +	SND_PCM_FORMAT_S32_LE,
> +};
> +
> +static const size_t test_formats_count =
> +	sizeof(test_formats) / sizeof(test_formats[0]);
> +
> +static void audio_state_init(struct audio_state *state, chamelium_data_t *data,
> +			     struct alsa *alsa, struct chamelium_port *port,
> +			     snd_pcm_format_t format, int channels, int rate)
> +{
> +	memset(state, 0, sizeof(*state));
> +	state->dump_fd = -1;
> +
> +	state->alsa = alsa;
> +	state->chamelium = data->chamelium;
> +	state->port = port;
> +
> +	state->playback.format = format;
> +	state->playback.channels = channels;
> +	state->playback.rate = rate;
> +
> +	alsa_configure_output(alsa, format, channels, rate);
> +
> +	state->stream = chamelium_stream_init();
> +	igt_assert_f(state->stream,
> +		     "Failed to initialize Chamelium stream client\n");
> +}
> +
> +static void audio_state_fini(struct audio_state *state)
> +{
> +	chamelium_stream_deinit(state->stream);
> +	free(state->name);
> +}
> +
> +static void *run_audio_thread(void *data)
> +{
> +	struct alsa *alsa = data;
> +
> +	alsa_run(alsa, -1);
> +	return NULL;
> +}
> +
> +static void audio_state_start(struct audio_state *state, const char *name)
> +{
> +	int ret;
> +	bool ok;
> +	size_t i, j;
> +	enum chamelium_stream_realtime_mode stream_mode;
> +	char dump_suffix[64];
> +
> +	free(state->name);
> +	state->name = strdup(name);
> +	state->recv_pages = 0;
> +	state->msec = 0;
> +
> +	igt_debug("Starting %s test with playback format %s, "
> +		  "sampling rate %d Hz and %d channels\n",
> +		  name, snd_pcm_format_name(state->playback.format),
> +		  state->playback.rate, state->playback.channels);
> +
> +	chamelium_start_capturing_audio(state->chamelium, state->port, false);
> +
> +	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
> +	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
> +	igt_assert_f(ok, "Failed to start streaming audio capture\n");
> +
> +	/* Start playing audio */
> +	state->run = true;
> +	ret = pthread_create(&state->thread, NULL, run_audio_thread,
> +			     state->alsa);
> +	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
> +
> +	/* The Chamelium device only supports this PCM format. */
> +	state->capture.format = SND_PCM_FORMAT_S32_LE;
> +
> +	/* Only after we've started playing audio, we can retrieve the capture
> +	 * format used by the Chamelium device. */
> +	chamelium_get_audio_format(state->chamelium, state->port,
> +				   &state->capture.rate,
> +				   &state->capture.channels);
> +	if (state->capture.rate == 0) {
> +		igt_debug("Audio receiver doesn't indicate the capture "
> +			  "sampling rate, assuming it's %d Hz\n",
> +			  state->playback.rate);
> +		state->capture.rate = state->playback.rate;
> +	}
> +
> +	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
> +					    state->channel_mapping);
> +	/* Make sure we can capture all channels we send. */
> +	for (i = 0; i < state->playback.channels; i++) {
> +		ok = false;
> +		for (j = 0; j < state->capture.channels; j++) {
> +			if (state->channel_mapping[j] == i) {
> +				ok = true;
> +				break;
> +			}
> +		}
> +		igt_assert_f(ok, "Cannot capture all channels\n");
> +	}
> +
> +	if (igt_frame_dump_is_enabled()) {
> +		snprintf(dump_suffix, sizeof(dump_suffix),
> +			 "capture-%s-%s-%dch-%dHz", name,
> +			 snd_pcm_format_name(state->playback.format),
> +			 state->playback.channels, state->playback.rate);
> +
> +		state->dump_fd = audio_create_wav_file_s32_le(
> +			dump_suffix, state->capture.rate,
> +			state->capture.channels, &state->dump_path);
> +		igt_assert_f(state->dump_fd >= 0,
> +			     "Failed to create audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_receive(struct audio_state *state, int32_t **recv,
> +				size_t *recv_len)
> +{
> +	bool ok;
> +	size_t page_count;
> +	size_t recv_size;
> +
> +	ok = chamelium_stream_receive_realtime_audio(state->stream, &page_count,
> +						     recv, recv_len);
> +	igt_assert_f(ok, "Failed to receive audio from stream server\n");
> +
> +	state->msec = state->recv_pages * *recv_len /
> +		      (double)state->capture.channels /
> +		      (double)state->capture.rate * 1000;
> +	state->recv_pages++;
> +
> +	if (state->dump_fd >= 0) {
> +		recv_size = *recv_len * sizeof(int32_t);
> +		igt_assert_f(write(state->dump_fd, *recv, recv_size) ==
> +				     recv_size,
> +			     "Failed to write to audio dump file\n");
> +	}
> +}
> +
> +static void audio_state_stop(struct audio_state *state, bool success)
> +{
> +	bool ok;
> +	int ret;
> +	struct chamelium_audio_file *audio_file;
> +	enum igt_log_level log_level;
> +
> +	igt_debug("Stopping audio playback\n");
> +	state->run = false;
> +	ret = pthread_join(state->thread, NULL);
> +	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
> +
> +	ok = chamelium_stream_stop_realtime_audio(state->stream);
> +	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
> +
> +	audio_file =
> +		chamelium_stop_capturing_audio(state->chamelium, state->port);
> +	if (audio_file) {
> +		igt_debug("Audio file saved on the Chamelium in %s\n",
> +			  audio_file->path);
> +		chamelium_destroy_audio_file(audio_file);
> +	}
> +
> +	if (state->dump_fd >= 0) {
> +		close(state->dump_fd);
> +		state->dump_fd = -1;
> +
> +		if (success) {
> +			/* Test succeeded, no need to keep the captured data */
> +			unlink(state->dump_path);
> +		} else
> +			igt_debug("Saved captured audio data to %s\n",
> +				  state->dump_path);
> +		free(state->dump_path);
> +		state->dump_path = NULL;
> +	}
> +
> +	if (success)
> +		log_level = IGT_LOG_DEBUG;
> +	else
> +		log_level = IGT_LOG_CRITICAL;
> +
> +	igt_log(IGT_LOG_DOMAIN, log_level,
> +		"Audio %s test result for format %s, "
> +		"sampling rate %d Hz and %d channels: %s\n",
> +		state->name, snd_pcm_format_name(state->playback.format),
> +		state->playback.rate, state->playback.channels,
> +		success ? "ALL GREEN" : "FAILED");
> +}
> +
> +static void check_audio_infoframe(struct audio_state *state)
> +{
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_audio infoframe_audio;
> +	struct infoframe_audio expected = { 0 };
> +	bool ok;
> +
> +	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "Chamelium board doesn't support GetLastInfoFrame\n");
> +		return;
> +	}
> +
> +	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
> +	expected.channel_count = state->playback.channels;
> +	expected.sampling_freq = state->playback.rate;
> +	expected.sample_size = snd_pcm_format_width(state->playback.format);
> +
> +	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
> +						 CHAMELIUM_INFOFRAME_AUDIO);
> +	if (infoframe == NULL && state->playback.channels <= 2) {
> +		/* Audio InfoFrames are optional for mono and stereo audio */
> +		igt_debug("Skipping audio InfoFrame check: "
> +			  "no InfoFrame received\n");
> +		return;
> +	}
> +	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
> +
> +	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
> +				   infoframe->payload, infoframe->payload_size);
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
> +
> +	igt_debug("Checking audio InfoFrame:\n");
> +	igt_debug("coding_type: got %d, expected %d\n",
> +		  infoframe_audio.coding_type, expected.coding_type);
> +	igt_debug("channel_count: got %d, expected %d\n",
> +		  infoframe_audio.channel_count, expected.channel_count);
> +	igt_debug("sampling_freq: got %d, expected %d\n",
> +		  infoframe_audio.sampling_freq, expected.sampling_freq);
> +	igt_debug("sample_size: got %d, expected %d\n",
> +		  infoframe_audio.sample_size, expected.sample_size);
> +
> +	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
> +		igt_assert(infoframe_audio.coding_type == expected.coding_type);
> +	if (infoframe_audio.channel_count >= 0)
> +		igt_assert(infoframe_audio.channel_count ==
> +			   expected.channel_count);
> +	if (infoframe_audio.sampling_freq >= 0)
> +		igt_assert(infoframe_audio.sampling_freq ==
> +			   expected.sampling_freq);
> +	if (infoframe_audio.sample_size >= 0)
> +		igt_assert(infoframe_audio.sample_size == expected.sample_size);
> +}
> +
> +static int audio_output_frequencies_callback(void *data, void *buffer,
> +					     int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	audio_signal_fill(state->signal, tmp, samples);
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool test_audio_frequencies(struct audio_state *state)
> +{
> +	int freq, step;
> +	int32_t *recv, *buf;
> +	double *channel;
> +	size_t i, j, streak;
> +	size_t recv_len, buf_len, buf_cap, channel_len;
> +	bool success;
> +	int capture_chan;
> +
> +	state->signal = audio_signal_init(state->playback.channels,
> +					  state->playback.rate);
> +	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
> +
> +	/* We'll choose different frequencies per channel to make sure they are
> +	 * independent from each other. To do so, we'll add a different offset
> +	 * to the base frequencies for each channel. We need to choose a big
> +	 * enough offset so that we're sure to detect mixed up channels. We
> +	 * choose an offset of two 2 bins in the final FFT to enforce a clear
> +	 * difference.
> +	 *
> +	 * Note that we assume capture_rate == playback_rate. We'll assert this
> +	 * later on. We cannot retrieve the capture rate before starting
> +	 * playing audio, so we don't really have the choice.
> +	 */
> +	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
> +	for (i = 0; i < test_frequencies_count; i++) {
> +		for (j = 0; j < state->playback.channels; j++) {
> +			freq = test_frequencies[i] + j * step;
> +			audio_signal_add_frequency(state->signal, freq, j);
> +		}
> +	}
> +	audio_signal_synthesize(state->signal);
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_frequencies_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	audio_state_start(state, "frequencies");
> +
> +	igt_assert_f(state->capture.rate == state->playback.rate,
> +		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
> +		     state->capture.rate, state->playback.rate);
> +
> +	/* Needs to be a multiple of 128, because that's the number of samples
> +	 * we get per channel each time we receive an audio page from the
> +	 * Chamelium device.
> +	 *
> +	 * Additionally, this value needs to be high enough to guarantee we
> +	 * capture a full period of each sine we generate. If we capture 2048
> +	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
> +	 * sines. For lower sampling rates, the capture duration will be
> +	 * longer.
> +	 */
> +	channel_len = CAPTURE_SAMPLES;
> +	channel = malloc(sizeof(double) * channel_len);
> +
> +	buf_cap = state->capture.channels * channel_len;
> +	buf = malloc(sizeof(int32_t) * buf_cap);
> +	buf_len = 0;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +
> +	success = false;
> +	streak = 0;
> +	while (!success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
> +		buf_len += recv_len;
> +
> +		if (buf_len < buf_cap)
> +			continue;
> +		igt_assert(buf_len == buf_cap);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (j = 0; j < state->playback.channels; j++) {
> +			capture_chan = state->channel_mapping[j];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  j, capture_chan);
> +
> +			audio_extract_channel_s32_le(channel, channel_len, buf,
> +						     buf_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			if (audio_signal_detect(state->signal,
> +						state->capture.rate, j, channel,
> +						channel_len))
> +				streak++;
> +			else
> +				streak = 0;
> +		}
> +
> +		buf_len = 0;
> +
> +		success = streak == MIN_STREAK * state->playback.channels;
> +	}
> +
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +	free(buf);
> +	free(channel);
> +	audio_signal_fini(state->signal);
> +
> +	check_audio_infoframe(state);
> +
> +	return success;
> +}
> +
> +static int audio_output_flatline_callback(void *data, void *buffer, int samples)
> +{
> +	struct audio_state *state = data;
> +	double *tmp;
> +	size_t len, i;
> +
> +	len = samples * state->playback.channels;
> +	tmp = malloc(len * sizeof(double));
> +	for (i = 0; i < len; i++)
> +		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	audio_convert_to(buffer, tmp, len, state->playback.format);
> +	free(tmp);
> +
> +	return state->run ? 0 : -1;
> +}
> +
> +static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
> +{
> +	double expected, min, max;
> +	size_t i;
> +	bool ok;
> +
> +	min = max = NAN;
> +	for (i = 0; i < buf_len; i++) {
> +		if (isnan(min) || buf[i] < min)
> +			min = buf[i];
> +		if (isnan(max) || buf[i] > max)
> +			max = buf[i];
> +	}
> +
> +	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
> +	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
> +	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
> +	if (ok)
> +		igt_debug("Flatline wave amplitude detected\n");
> +	else
> +		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
> +			  min, max);
> +	return ok;
> +}
> +
> +static ssize_t detect_falling_edge(double *buf, size_t buf_len)
> +{
> +	size_t i;
> +
> +	for (i = 0; i < buf_len; i++) {
> +		if (buf[i] < 0)
> +			return i;
> +	}
> +
> +	return -1;
> +}
> +
> +/** test_audio_flatline:
> + *
> + * Send a constant value (one positive, then a negative one) and check that:
> + *
> + * - The amplitude of the flatline is correct
> + * - All channels switch from a positive signal to a negative one at the same
> + *   time (ie. all channels are aligned)
> + */
> +static bool test_audio_flatline(struct audio_state *state)
> +{
> +	bool success, amp_success, align_success;
> +	int32_t *recv;
> +	size_t recv_len, i, channel_len;
> +	ssize_t j;
> +	int streak, capture_chan;
> +	double *channel;
> +	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
> +
> +	alsa_register_output_callback(state->alsa,
> +				      audio_output_flatline_callback, state,
> +				      PLAYBACK_SAMPLES);
> +
> +	/* Start by sending a positive signal */
> +	state->positive = true;
> +
> +	audio_state_start(state, "flatline");
> +
> +	for (i = 0; i < state->playback.channels; i++)
> +		falling_edges[i] = -1;
> +
> +	recv = NULL;
> +	recv_len = 0;
> +	amp_success = false;
> +	streak = 0;
> +	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
> +		audio_state_receive(state, &recv, &recv_len);
> +
> +		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
> +
> +		for (i = 0; i < state->playback.channels; i++) {
> +			capture_chan = state->channel_mapping[i];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n",
> +				  i, capture_chan);
> +
> +			channel_len = audio_extract_channel_s32_le(
> +				NULL, 0, recv, recv_len,
> +				state->capture.channels, capture_chan);
> +			channel = malloc(channel_len * sizeof(double));
> +			audio_extract_channel_s32_le(channel, channel_len, recv,
> +						     recv_len,
> +						     state->capture.channels,
> +						     capture_chan);
> +
> +			/* Check whether the amplitude is fine */
> +			if (detect_flatline_amplitude(channel, channel_len,
> +						      state->positive))
> +				streak++;
> +			else
> +				streak = 0;
> +
> +			/* If we're now sending a negative signal, detect the
> +			 * falling edge */
> +			j = detect_falling_edge(channel, channel_len);
> +			if (!state->positive && j >= 0) {
> +				falling_edges[i] =
> +					recv_len * state->recv_pages + j;
> +			}
> +
> +			free(channel);
> +		}
> +
> +		amp_success = streak == MIN_STREAK * state->playback.channels;
> +
> +		if (amp_success && state->positive) {
> +			/* Switch to a negative signal after we've detected the
> +			 * positive one. */
> +			state->positive = false;
> +			amp_success = false;
> +			streak = 0;
> +			igt_debug("Switching to negative square wave\n");
> +		}
> +	}
> +
> +	/* Check alignment between all channels by comparing the index of the
> +	 * falling edge. */
> +	align_success = true;
> +	for (i = 0; i < state->playback.channels; i++) {
> +		if (falling_edges[i] < 0) {
> +			igt_critical(
> +				"Falling edge not detected for channel %zu\n",
> +				i);
> +			align_success = false;
> +			continue;
> +		}
> +
> +		if (abs(falling_edges[0] - falling_edges[i]) >
> +		    FLATLINE_ALIGN_ACCURACY) {
> +			igt_critical("Channel alignment mismatch: "
> +				     "channel 0 has a falling edge at index %d "
> +				     "while channel %zu has index %d\n",
> +				     falling_edges[0], i, falling_edges[i]);
> +			align_success = false;
> +		}
> +	}
> +
> +	success = amp_success && align_success;
> +	audio_state_stop(state, success);
> +
> +	free(recv);
> +
> +	return success;
> +}
> +
> +static bool check_audio_configuration(struct alsa *alsa,
> +				      snd_pcm_format_t format, int channels,
> +				      int sampling_rate)
> +{
> +	if (!alsa_test_output_configuration(alsa, format, channels,
> +					    sampling_rate)) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because at least one of the "
> +			  "selected output devices doesn't support this "
> +			  "configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	/* TODO: the Chamelium device sends a malformed signal for some audio
> +	 * configurations. See crbug.com/950917 */
> +	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
> +	    channels > 2) {
> +		igt_debug("Skipping test with format %s, sampling rate %d Hz "
> +			  "and %d channels because the Chamelium device "
> +			  "doesn't support this configuration\n",
> +			  snd_pcm_format_name(format), sampling_rate, channels);
> +		return false;
> +	}
> +	return true;
> +}
> +
> +static const char test_display_audio_desc[] =
> +	"Playback various audio signals with various audio formats/rates, "
> +	"capture them and check they are correct";
> +static void test_display_audio(chamelium_data_t *data,
> +			       struct chamelium_port *port,
> +			       const char *audio_device,
> +			       enum igt_custom_edid_type edid)
> +{
> +	bool run, success;
> +	struct alsa *alsa;
> +	int ret;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id, i, j;
> +	int channels, sampling_rate;
> +	snd_pcm_format_t format;
> +	struct audio_state state;
> +
> +	igt_require(alsa_has_exclusive_access());
> +
> +	/* Old Chamelium devices need an update for DisplayPort audio and
> +	 * chamelium_get_audio_format support. */
> +	igt_require(chamelium_has_audio_support(data->chamelium, port));
> +
> +	alsa = alsa_init();
> +	igt_assert(alsa);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because the receiver won't try to receive audio if
> +	 * it doesn't receive video. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	run = false;
> +	success = true;
> +	for (i = 0; i < test_sampling_rates_count; i++) {
> +		for (j = 0; j < test_formats_count; j++) {
> +			ret = alsa_open_output(alsa, audio_device);
> +			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
> +
> +			/* TODO: playback on all 8 available channels (this
> +			 * isn't supported by Chamelium devices yet, see
> +			 * https://crbug.com/950917) */
> +			format = test_formats[j];
> +			channels = PLAYBACK_CHANNELS;
> +			sampling_rate = test_sampling_rates[i];
> +
> +			if (!check_audio_configuration(alsa, format, channels,
> +						       sampling_rate))
> +				continue;
> +
> +			run = true;
> +
> +			audio_state_init(&state, data, alsa, port, format,
> +					 channels, sampling_rate);
> +			success &= test_audio_frequencies(&state);
> +			success &= test_audio_flatline(&state);
> +			audio_state_fini(&state);
> +
> +			alsa_close_output(alsa);
> +		}
> +	}
> +
> +	/* Make sure we tested at least one frequency and format. */
> +	igt_assert(run);
> +	/* Make sure all runs were successful. */
> +	igt_assert(success);
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +
> +	free(alsa);
> +}
> +
> +static const char test_display_audio_edid_desc[] =
> +	"Plug a connector with an EDID suitable for audio, check ALSA's "
> +	"EDID-Like Data reports the correct audio parameters";
> +static void test_display_audio_edid(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_custom_edid_type edid)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fb;
> +	drmModeModeInfo *mode;
> +	drmModeConnector *connector;
> +	int fb_id;
> +	struct eld_entry eld;
> +	struct eld_sad *sad;
> +
> +	igt_require(eld_is_supported());
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, edid);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	/* Enable the output because audio cannot be played on inactive
> +	 * connectors. */
> +	igt_assert(connector->count_modes > 0);
> +	mode = &connector->modes[0];
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	igt_assert(eld_get_igt(&eld));
> +	igt_assert(eld.sads_len == 1);
> +
> +	sad = &eld.sads[0];
> +	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
> +	igt_assert(sad->channels == 2);
> +	igt_assert(sad->rates ==
> +		   (CEA_SAD_SAMPLING_RATE_32KHZ | CEA_SAD_SAMPLING_RATE_44KHZ |
> +		    CEA_SAD_SAMPLING_RATE_48KHZ));
> +	igt_assert(sad->bits ==
> +		   (CEA_SAD_SAMPLE_SIZE_16 | CEA_SAD_SAMPLE_SIZE_20 |
> +		    CEA_SAD_SAMPLE_SIZE_24));
> +
> +	igt_remove_fb(data->drm_fd, &fb);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing Audio with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("dp-audio", DisplayPort) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_DP_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("dp-audio-edid", DisplayPort)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_DP_AUDIO);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_audio_desc);
> +		connector_subtest("hdmi-audio", HDMIA) test_display_audio(
> +			&data, port, "HDMI", IGT_CUSTOM_EDID_HDMI_AUDIO);
> +
> +		igt_describe(test_display_audio_edid_desc);
> +		connector_subtest("hdmi-audio-edid", HDMIA)
> +			test_display_audio_edid(&data, port,
> +						IGT_CUSTOM_EDID_HDMI_AUDIO);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_color_chamelium.c b/tests/chamelium/kms_chamelium_color.c
> similarity index 100%
> rename from tests/chamelium/kms_color_chamelium.c
> rename to tests/chamelium/kms_chamelium_color.c
> diff --git a/tests/chamelium/kms_chamelium_edid.c b/tests/chamelium/kms_chamelium_edid.c
> new file mode 100644
> index 00000000..d6b6045e
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_edid.c
> @@ -0,0 +1,535 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the EDID functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include <stdint.h>
> +#include <xf86drmMode.h>
> +
> +#include "igt_chamelium.h"
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +#include "monitor_edids/dp_edids.h"
> +#include "monitor_edids/hdmi_edids.h"
> +#include "monitor_edids/monitor_edids_helper.h"
> +
> +#define MODE_CLOCK_ACCURACY 0.05 /* 5% */
> +
> +static void get_connectors_link_status_failed(chamelium_data_t *data,
> +					      bool *link_status_failed)
> +{
> +	drmModeConnector *connector;
> +	uint64_t link_status;
> +	drmModePropertyPtr prop;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		connector = chamelium_port_get_connector(data->chamelium,
> +							 data->ports[p], false);
> +
> +		igt_assert(kmstest_get_property(
> +			data->drm_fd, connector->connector_id,
> +			DRM_MODE_OBJECT_CONNECTOR, "link-status", NULL,
> +			&link_status, &prop));
> +
> +		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
> +
> +		drmModeFreeProperty(prop);
> +		drmModeFreeConnector(connector);
> +	}
> +}
> +
> +static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
> +		       drmModeModeInfo *mode)
> +{
> +	struct chamelium_video_params video_params = { 0 };
> +	double mode_clock;
> +	int mode_hsync_offset, mode_vsync_offset;
> +	int mode_hsync_width, mode_vsync_width;
> +	int mode_hsync_polarity, mode_vsync_polarity;
> +
> +	chamelium_port_get_video_params(chamelium, port, &video_params);
> +
> +	mode_clock = (double)mode->clock / 1000;
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_DisplayPort) {
> +		/* this is what chamelium understands as offsets for DP */
> +		mode_hsync_offset = mode->htotal - mode->hsync_start;
> +		mode_vsync_offset = mode->vtotal - mode->vsync_start;
> +	} else {
> +		/* and this is what they are for other connectors */
> +		mode_hsync_offset = mode->hsync_start - mode->hdisplay;
> +		mode_vsync_offset = mode->vsync_start - mode->vdisplay;
> +	}
> +
> +	mode_hsync_width = mode->hsync_end - mode->hsync_start;
> +	mode_vsync_width = mode->vsync_end - mode->vsync_start;
> +
> +	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
> +	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
> +
> +	igt_debug("Checking video mode:\n");
> +	igt_debug("clock: got %f, expected %f ± %f%%\n", video_params.clock,
> +		  mode_clock, MODE_CLOCK_ACCURACY * 100);
> +	igt_debug("hactive: got %d, expected %d\n", video_params.hactive,
> +		  mode->hdisplay);
> +	igt_debug("vactive: got %d, expected %d\n", video_params.vactive,
> +		  mode->vdisplay);
> +	igt_debug("hsync_offset: got %d, expected %d\n",
> +		  video_params.hsync_offset, mode_hsync_offset);
> +	igt_debug("vsync_offset: got %d, expected %d\n",
> +		  video_params.vsync_offset, mode_vsync_offset);
> +	igt_debug("htotal: got %d, expected %d\n", video_params.htotal,
> +		  mode->htotal);
> +	igt_debug("vtotal: got %d, expected %d\n", video_params.vtotal,
> +		  mode->vtotal);
> +	igt_debug("hsync_width: got %d, expected %d\n",
> +		  video_params.hsync_width, mode_hsync_width);
> +	igt_debug("vsync_width: got %d, expected %d\n",
> +		  video_params.vsync_width, mode_vsync_width);
> +	igt_debug("hsync_polarity: got %d, expected %d\n",
> +		  video_params.hsync_polarity, mode_hsync_polarity);
> +	igt_debug("vsync_polarity: got %d, expected %d\n",
> +		  video_params.vsync_polarity, mode_vsync_polarity);
> +
> +	if (!isnan(video_params.clock)) {
> +		igt_assert(video_params.clock >
> +			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
> +		igt_assert(video_params.clock <
> +			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
> +	}
> +	igt_assert(video_params.hactive == mode->hdisplay);
> +	igt_assert(video_params.vactive == mode->vdisplay);
> +	igt_assert(video_params.hsync_offset == mode_hsync_offset);
> +	igt_assert(video_params.vsync_offset == mode_vsync_offset);
> +	igt_assert(video_params.htotal == mode->htotal);
> +	igt_assert(video_params.vtotal == mode->vtotal);
> +	igt_assert(video_params.hsync_width == mode_hsync_width);
> +	igt_assert(video_params.vsync_width == mode_vsync_width);
> +	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
> +	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
> +}
> +
> +static const char igt_custom_edid_type_read_desc[] =
> +	"Make sure the EDID exposed by KMS is the same as the screen's";
> +static void igt_custom_edid_type_read(chamelium_data_t *data,
> +				      struct chamelium_port *port,
> +				      enum igt_custom_edid_type edid)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector;
> +	size_t raw_edid_size;
> +	const struct edid *raw_edid;
> +	uint64_t edid_blob_id;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_skip_on(chamelium_check_analog_bridge(data, port));
> +
> +	connector = chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob_id != 0);
> +	edid_blob = drmModeGetPropertyBlob(data->drm_fd, edid_blob_id);
> +	igt_assert(edid_blob);
> +
> +	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
> +	raw_edid_size = edid_get_size(raw_edid);
> +	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +}
> +
> +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(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   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;
> +
> +		monitor_edid *edid = &edids_list[i];
> +		igt_info("Testing out the EDID for %s\n",
> +			 monitor_edid_get_name(edid));
> +
> +		/* Getting and Setting the EDID on Chamelium. */
> +		chamelium_edid =
> +			get_chameleon_edid_from_monitor_edid(chamelium, 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);
> +		chamelium_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 = chamelium_get_mode_for_port(chamelium, port);
> +		chamelium_create_fb_for_mode(data, &fb, &mode);
> +		output = chamelium_get_output_for_port(data, port);
> +		pipe = chamelium_get_pipe_for_output(&data->display, output);
> +		igt_output_set_pipe(output, pipe);
> +		chamelium_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);
> +}
> +
> +static const char igt_edid_resolution_list_desc[] =
> +	"Get an EDID with many modes of different configurations, set them on the screen and check the"
> +	" screen resolution matches the mode resolution.";
> +
> +static void edid_resolution_list(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct chamelium *chamelium = data->chamelium;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	drmModeConnector *connector;
> +	drmModeModeInfoPtr modes;
> +	int count_modes;
> +	int i;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	chamelium_unplug(chamelium, port);
> +	chamelium_set_edid(data, port, IGT_CUSTOM_EDID_FULL);
> +
> +	igt_flush_uevents(mon);
> +	chamelium_plug(chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_CONNECTED);
> +	igt_flush_uevents(mon);
> +
> +	connector = chamelium_port_get_connector(chamelium, port, true);
> +	modes = connector->modes;
> +	count_modes = connector->count_modes;
> +
> +	output = chamelium_get_output_for_port(data, port);
> +	pipe = chamelium_get_pipe_for_output(&data->display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	for (i = 0; i < count_modes; ++i)
> +		igt_debug("#%d %s %uHz\n", i, modes[i].name, modes[i].vrefresh);
> +
> +	for (i = 0; i < count_modes; ++i) {
> +		struct igt_fb fb = { 0 };
> +		bool is_video_stable;
> +		int screen_res_w, screen_res_h;
> +
> +		igt_info("Testing #%d %s %uHz\n", i, modes[i].name,
> +			 modes[i].vrefresh);
> +
> +		/* Set the screen mode with the one we chose. */
> +		chamelium_create_fb_for_mode(data, &fb, &modes[i]);
> +		chamelium_enable_output(data, port, output, &modes[i], &fb);
> +		is_video_stable = chamelium_port_wait_video_input_stable(
> +			chamelium, port, 10);
> +		igt_assert(is_video_stable);
> +
> +		chamelium_port_get_resolution(chamelium, port, &screen_res_w,
> +					      &screen_res_h);
> +		igt_assert_eq(screen_res_w, modes[i].hdisplay);
> +		igt_assert_eq(screen_res_h, modes[i].vdisplay);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_suspend_resume_edid_change_desc[] =
> +	"Simulate a screen being unplugged and another screen being plugged "
> +	"during suspend, check that a uevent is sent and connector status is "
> +	"updated";
> +static void test_suspend_resume_edid_change(chamelium_data_t *data,
> +					    struct chamelium_port *port,
> +					    enum igt_suspend_state state,
> +					    enum igt_suspend_test test,
> +					    enum igt_custom_edid_type edid,
> +					    enum igt_custom_edid_type alt_edid)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	bool link_status_failed[2][data->port_count];
> +	int p;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Catch the event and flush all remaining ones. */
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_flush_uevents(mon);
> +
> +	/* First plug in the port */
> +	chamelium_set_edid(data, port, edid);
> +	chamelium_plug(data->chamelium, port);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	/*
> +	 * Change the edid before we suspend. On resume, the machine should
> +	 * notice the EDID change and fire a hotplug event.
> +	 */
> +	chamelium_set_edid(data, port, alt_edid);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[0]);
> +
> +	igt_flush_uevents(mon);
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	get_connectors_link_status_failed(data, link_status_failed[1]);
> +
> +	for (p = 0; p < data->port_count; p++)
> +		igt_skip_on(!link_status_failed[0][p] &&
> +			    link_status_failed[1][p]);
> +}
> +
> +static const char test_mode_timings_desc[] =
> +	"For each mode of the IGT base EDID, perform a modeset and check the "
> +	"mode detected by the Chamelium receiver matches the mode we set";
> +static void test_mode_timings(chamelium_data_t *data,
> +			      struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	igt_require(chamelium_supports_get_video_params(data->chamelium));
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +		int fb_id;
> +		struct igt_fb fb;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		/* Trigger the FSM */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
> +
> +		check_mode(data->chamelium, port, mode);
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing EDID with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("dp-edid-read", DisplayPort)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-4k", DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_4K,
> +					       ARRAY_SIZE(DP_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("dp-edid-stress-resolution-non-4k",
> +				  DisplayPort)
> +			edid_stress_resolution(&data, port, DP_EDIDS_NON_4K,
> +					       ARRAY_SIZE(DP_EDIDS_NON_4K));
> +
> +		igt_describe(igt_edid_resolution_list_desc);
> +		connector_subtest("dp-edid-resolution-list", DisplayPort)
> +			edid_resolution_list(&data, port);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("dp-edid-change-during-hibernate",
> +				  DisplayPort)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("dp-mode-timings", DisplayPort)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("hdmi-edid-read", HDMIA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_4K));
> +
> +		igt_describe(igt_edid_stress_resolution_desc);
> +		connector_subtest("hdmi-edid-stress-resolution-non-4k", HDMIA)
> +			edid_stress_resolution(&data, port, HDMI_EDIDS_NON_4K,
> +					       ARRAY_SIZE(HDMI_EDIDS_NON_4K));
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_MEM,
> +							SUSPEND_TEST_NONE,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_suspend_resume_edid_change_desc);
> +		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
> +			test_suspend_resume_edid_change(&data, port,
> +							SUSPEND_STATE_DISK,
> +							SUSPEND_TEST_DEVICES,
> +							IGT_CUSTOM_EDID_BASE,
> +							IGT_CUSTOM_EDID_ALT);
> +
> +		igt_describe(test_mode_timings_desc);
> +		connector_subtest("hdmi-mode-timings", HDMIA)
> +			test_mode_timings(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(igt_custom_edid_type_read_desc);
> +		connector_subtest("vga-edid-read", VGA)
> +		{
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +			igt_custom_edid_type_read(&data, port,
> +						  IGT_CUSTOM_EDID_ALT);
> +		}
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_frames.c b/tests/chamelium/kms_chamelium_frames.c
> new file mode 100644
> index 00000000..008bc34b
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_frames.c
> @@ -0,0 +1,1085 @@
> +/*
> + * Copyright © 2016 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Lyude Paul <lyude@redhat.com>
> + */
> +
> +#include "igt_eld.h"
> +#include "igt_infoframe.h"
> +#include "kms_chamelium_helper.h"
> +
> +#define connector_dynamic_subtest(name__, type__)                   \
> +	igt_subtest_with_dynamic(name__)                            \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +struct vic_mode {
> +	int hactive, vactive;
> +	int vrefresh; /* Hz */
> +	uint32_t picture_ar;
> +};
> +
> +static int chamelium_vga_modes[][2] = {
> +	{ 1600, 1200 }, { 1920, 1200 }, { 1920, 1080 }, { 1680, 1050 },
> +	{ 1280, 1024 }, { 1280, 960 },	{ 1440, 900 },	{ 1280, 800 },
> +	{ 1024, 768 },	{ 1360, 768 },	{ 1280, 720 },	{ 800, 600 },
> +	{ 640, 480 },	{ -1, -1 },
> +};
> +
> +/* Maps Video Identification Codes to a mode */
> +static const struct vic_mode vic_modes[] = {
> +	[16] = {
> +		.hactive = 1920,
> +		.vactive = 1080,
> +		.vrefresh = 60,
> +		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
> +	},
> +};
> +
> +/* Maps aspect ratios to their mode flag */
> +static const uint32_t mode_ar_flags[] = {
> +	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
> +};
> +
> +static bool prune_vga_mode(chamelium_data_t *data, drmModeModeInfo *mode)
> +{
> +	int i = 0;
> +
> +	while (chamelium_vga_modes[i][0] != -1) {
> +		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
> +		    mode->vdisplay == chamelium_vga_modes[i][1])
> +			return false;
> +
> +		i++;
> +	}
> +
> +	return true;
> +}
> +
> +static void do_test_display(chamelium_data_t *data, struct chamelium_port *port,
> +			    igt_output_t *output, drmModeModeInfo *mode,
> +			    uint32_t fourcc, enum chamelium_check check,
> +			    int count)
> +{
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	struct igt_fb frame_fb, fb;
> +	int i, fb_id, captured_frame_count;
> +	int frame_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &fb);
> +	igt_assert(fb_id > 0);
> +
> +	frame_id =
> +		igt_fb_convert(&frame_fb, &fb, fourcc, DRM_FORMAT_MOD_LINEAR);
> +	igt_assert(frame_id > 0);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&fb);
> +
> +	chamelium_enable_output(data, port, output, mode, &frame_fb);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		igt_crc_t *expected_crc;
> +		igt_crc_t *crc;
> +
> +		/* We want to keep the display running for a little bit, since
> +		 * there's always the potential the driver isn't able to keep
> +		 * the display running properly for very long
> +		 */
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == count);
> +
> +		igt_debug("Captured %d frames\n", captured_frame_count);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		for (i = 0; i < captured_frame_count; i++)
> +			chamelium_assert_crc_eq_or_dump(
> +				data->chamelium, expected_crc, &crc[i], &fb, i);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_ANALOG ||
> +		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		igt_assert(count == 1);
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG)
> +			chamelium_crop_analog_frame(dump, mode->hdisplay,
> +						    mode->vdisplay);
> +
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	igt_remove_fb(data->drm_fd, &frame_fb);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static enum infoframe_avi_picture_aspect_ratio
> +get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
> +{
> +	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
> +	switch (aspect_ratio) {
> +	case DRM_MODE_PICTURE_ASPECT_4_3:
> +		return INFOFRAME_AVI_PIC_AR_4_3;
> +	case DRM_MODE_PICTURE_ASPECT_16_9:
> +		return INFOFRAME_AVI_PIC_AR_16_9;
> +	default:
> +		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
> +	}
> +}
> +
> +static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
> +				 drmModeModeInfo *drm_mode)
> +{
> +	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
> +
> +	return vic_mode->hactive == drm_mode->hdisplay &&
> +	       vic_mode->vactive == drm_mode->vdisplay &&
> +	       vic_mode->vrefresh == drm_mode->vrefresh &&
> +	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
> +}
> +
> +static void randomize_plane_stride(chamelium_data_t *data, uint32_t width,
> +				   uint32_t height, uint32_t format,
> +				   uint64_t modifier, size_t *stride)
> +{
> +	size_t stride_min;
> +	uint32_t max_tile_w = 4, tile_w, tile_h;
> +	int i;
> +	struct igt_fb dummy;
> +
> +	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
> +
> +	/* Randomize the stride to less than twice the minimum. */
> +	*stride = (rand() % stride_min) + stride_min;
> +
> +	/*
> +	 * Create a dummy FB to determine bpp for each plane, and calculate
> +	 * the maximum tile width from that.
> +	 */
> +	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
> +	for (i = 0; i < dummy.num_planes; i++) {
> +		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i],
> +				     &tile_w, &tile_h);
> +
> +		if (tile_w > max_tile_w)
> +			max_tile_w = tile_w;
> +	}
> +	igt_remove_fb(data->drm_fd, &dummy);
> +
> +	/*
> +	 * Pixman requires the stride to be aligned to 32-bits, which is
> +	 * reflected in the initial value of max_tile_w and the hw
> +	 * may require a multiple of tile width, choose biggest of the 2.
> +	 */
> +	*stride = ALIGN(*stride, max_tile_w);
> +}
> +
> +static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
> +				  uint32_t height, uint32_t format,
> +				  uint64_t *modifier)
> +{
> +	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
> +		/* Randomize the column height to less than twice the minimum.
> +		 */
> +		size_t column_height = (rand() % height) + height;
> +
> +		igt_debug(
> +			"Selecting VC4 SAND256 tiling with column height %ld\n",
> +			column_height);
> +
> +		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(
> +			column_height);
> +	}
> +}
> +
> +static void randomize_plane_setup(chamelium_data_t *data, igt_plane_t *plane,
> +				  drmModeModeInfo *mode, uint32_t *width,
> +				  uint32_t *height, uint32_t *format,
> +				  uint64_t *modifier, bool allow_yuv)
> +{
> +	int min_dim;
> +	uint32_t idx[plane->format_mod_count];
> +	unsigned int count = 0;
> +	unsigned int i;
> +
> +	/* First pass to count the supported formats. */
> +	for (i = 0; i < plane->format_mod_count; i++)
> +		if (igt_fb_supported_format(plane->formats[i]) &&
> +		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
> +			idx[count++] = i;
> +
> +	igt_assert(count > 0);
> +
> +	i = idx[rand() % count];
> +	*format = plane->formats[i];
> +	*modifier = plane->modifiers[i];
> +
> +	update_tiled_modifier(plane, *width, *height, *format, modifier);
> +
> +	/*
> +	 * Randomize width and height in the mode dimensions range.
> +	 *
> +	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
> +	 * least min_dim, because src_w = width - (rand % w / 2).
> +	 *
> +	 * Use a minimum dimension of 16 for YUV, because planar YUV
> +	 * subsamples the UV plane.
> +	 */
> +	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
> +
> +	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
> +	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
> +}
> +
> +static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
> +			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
> +			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
> +			    struct igt_fb *fb)
> +{
> +	igt_plane_set_fb(plane, fb);
> +
> +	igt_plane_set_position(plane, crtc_x, crtc_y);
> +	igt_plane_set_size(plane, crtc_w, crtc_h);
> +
> +	igt_fb_set_position(fb, plane, src_x, src_y);
> +	igt_fb_set_size(fb, plane, src_w, src_h);
> +}
> +
> +static void randomize_plane_coordinates(
> +	chamelium_data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
> +	struct igt_fb *fb, uint32_t *src_w, uint32_t *src_h, uint32_t *src_x,
> +	uint32_t *src_y, uint32_t *crtc_w, uint32_t *crtc_h, int32_t *crtc_x,
> +	int32_t *crtc_y, bool allow_scaling)
> +{
> +	bool is_yuv = igt_format_is_yuv(fb->drm_format);
> +	uint32_t width = fb->width, height = fb->height;
> +	double ratio;
> +	int ret;
> +
> +	/* Randomize source offset in the first half of the original size. */
> +	*src_x = rand() % (width / 2);
> +	*src_y = rand() % (height / 2);
> +
> +	/* The source size only includes the active source area. */
> +	*src_w = width - *src_x;
> +	*src_h = height - *src_y;
> +
> +	if (allow_scaling) {
> +		*crtc_w = (rand() % mode->hdisplay) + 1;
> +		*crtc_h = (rand() % mode->vdisplay) + 1;
> +
> +		/*
> +		 * Don't bother with scaling if dimensions are quite close in
> +		 * order to get non-scaling cases more frequently. Also limit
> +		 * scaling to 3x to avoid aggressive filtering that makes
> +		 * comparison less reliable, and don't go above 2x downsampling
> +		 * to avoid possible hw limitations.
> +		 */
> +
> +		ratio = ((double)*crtc_w / *src_w);
> +		if (ratio < 0.5)
> +			*src_w = *crtc_w * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_w = *src_w;
> +		else if (ratio > 3.0)
> +			*crtc_w = *src_w * 3;
> +
> +		ratio = ((double)*crtc_h / *src_h);
> +		if (ratio < 0.5)
> +			*src_h = *crtc_h * 2;
> +		else if (ratio > 0.8 && ratio < 1.2)
> +			*crtc_h = *src_h;
> +		else if (ratio > 3.0)
> +			*crtc_h = *src_h * 3;
> +	} else {
> +		*crtc_w = *src_w;
> +		*crtc_h = *src_h;
> +	}
> +
> +	if (*crtc_w != *src_w || *crtc_h != *src_h) {
> +		/*
> +		 * When scaling is involved, make sure to not go off-bounds or
> +		 * scaled clipping may result in decimal dimensions, that most
> +		 * drivers don't support.
> +		 */
> +		if (*crtc_w < mode->hdisplay)
> +			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
> +		else
> +			*crtc_x = 0;
> +
> +		if (*crtc_h < mode->vdisplay)
> +			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
> +		else
> +			*crtc_y = 0;
> +	} else {
> +		/*
> +		 * Randomize the on-crtc position and allow the plane to go
> +		 * off-display by less than half of its on-crtc dimensions.
> +		 */
> +		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
> +		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
> +	}
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	ret = igt_display_try_commit_atomic(
> +		&data->display,
> +		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
> +		NULL);
> +	if (!ret)
> +		return;
> +
> +	/* Coordinates are logged in the dumped debug log, so only report w/h on
> +	 * failure here. */
> +	igt_assert_f(ret != -ENOSPC,
> +		     "Failure in testcase, invalid coordinates on a %ux%u fb\n",
> +		     width, height);
> +
> +	/* Make YUV coordinates a multiple of 2 and retry the math. */
> +	if (is_yuv) {
> +		*src_x &= ~1;
> +		*src_y &= ~1;
> +		*src_w &= ~1;
> +		*src_h &= ~1;
> +		/* To handle 1:1 scaling, clear crtc_w/h too. */
> +		*crtc_w &= ~1;
> +		*crtc_h &= ~1;
> +
> +		if (*crtc_x < 0 && (*crtc_x & 1))
> +			(*crtc_x)++;
> +		else
> +			*crtc_x &= ~1;
> +
> +		/* If negative, round up to 0 instead of down */
> +		if (*crtc_y < 0 && (*crtc_y & 1))
> +			(*crtc_y)++;
> +		else
> +			*crtc_y &= ~1;
> +
> +		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
> +				*crtc_h, *crtc_x, *crtc_y, fb);
> +		ret = igt_display_try_commit_atomic(
> +			&data->display,
> +			DRM_MODE_ATOMIC_TEST_ONLY |
> +				DRM_MODE_ATOMIC_ALLOW_MODESET,
> +			NULL);
> +		if (!ret)
> +			return;
> +	}
> +
> +	igt_assert(!ret || allow_scaling);
> +	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
> +		 ((double)*crtc_w / *src_w), ((double)*crtc_h / *src_h));
> +
> +	*crtc_w = *src_w;
> +	*crtc_h = *src_h;
> +
> +	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w, *crtc_h,
> +			*crtc_x, *crtc_y, fb);
> +	igt_display_commit_atomic(&data->display,
> +				  DRM_MODE_ATOMIC_TEST_ONLY |
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET,
> +				  NULL);
> +}
> +
> +static void blit_plane_cairo(chamelium_data_t *data, cairo_surface_t *result,
> +			     uint32_t src_w, uint32_t src_h, uint32_t src_x,
> +			     uint32_t src_y, uint32_t crtc_w, uint32_t crtc_h,
> +			     int32_t crtc_x, int32_t crtc_y, struct igt_fb *fb)
> +{
> +	cairo_surface_t *surface;
> +	cairo_surface_t *clipped_surface;
> +	cairo_t *cr;
> +
> +	surface = igt_get_cairo_surface(data->drm_fd, fb);
> +
> +	if (src_x || src_y) {
> +		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
> +							     src_w, src_h);
> +
> +		cr = cairo_create(clipped_surface);
> +
> +		cairo_translate(cr, -1. * src_x, -1. * src_y);
> +
> +		cairo_set_source_surface(cr, surface, 0, 0);
> +
> +		cairo_paint(cr);
> +		cairo_surface_flush(clipped_surface);
> +
> +		cairo_destroy(cr);
> +	} else {
> +		clipped_surface = surface;
> +	}
> +
> +	cr = cairo_create(result);
> +
> +	cairo_translate(cr, crtc_x, crtc_y);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_scale(cr, (double)crtc_w / src_w, (double)crtc_h / src_h);
> +	}
> +
> +	cairo_set_source_surface(cr, clipped_surface, 0, 0);
> +	cairo_surface_destroy(clipped_surface);
> +
> +	if (src_w != crtc_w || src_h != crtc_h) {
> +		cairo_pattern_set_filter(cairo_get_source(cr),
> +					 CAIRO_FILTER_BILINEAR);
> +		cairo_pattern_set_extend(cairo_get_source(cr),
> +					 CAIRO_EXTEND_NONE);
> +	}
> +
> +	cairo_paint(cr);
> +	cairo_surface_flush(result);
> +
> +	cairo_destroy(cr);
> +}
> +
> +static void prepare_randomized_plane(chamelium_data_t *data,
> +				     drmModeModeInfo *mode, igt_plane_t *plane,
> +				     struct igt_fb *overlay_fb,
> +				     unsigned int index,
> +				     cairo_surface_t *result_surface,
> +				     bool allow_scaling, bool allow_yuv)
> +{
> +	struct igt_fb pattern_fb;
> +	uint32_t overlay_fb_w, overlay_fb_h;
> +	uint32_t overlay_src_w, overlay_src_h;
> +	uint32_t overlay_src_x, overlay_src_y;
> +	int32_t overlay_crtc_x, overlay_crtc_y;
> +	uint32_t overlay_crtc_w, overlay_crtc_h;
> +	uint32_t format;
> +	uint64_t modifier;
> +	size_t stride;
> +	bool tiled;
> +	int fb_id;
> +
> +	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
> +			      &format, &modifier, allow_yuv);
> +
> +	tiled = (modifier != DRM_FORMAT_MOD_LINEAR);
> +	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n", index,
> +		  overlay_fb_w, overlay_fb_h, igt_format_str(format),
> +		  tiled ? "tiled" : "linear");
> +
> +	/* Get a pattern framebuffer for the overlay plane. */
> +	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
> +					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h, format,
> +			       modifier, &stride);
> +
> +	igt_debug("Plane %d: stride %ld\n", index, stride);
> +
> +	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
> +					   modifier, stride);
> +	igt_assert(fb_id > 0);
> +
> +	randomize_plane_coordinates(data, plane, mode, overlay_fb,
> +				    &overlay_src_w, &overlay_src_h,
> +				    &overlay_src_x, &overlay_src_y,
> +				    &overlay_crtc_w, &overlay_crtc_h,
> +				    &overlay_crtc_x, &overlay_crtc_y,
> +				    allow_scaling);
> +
> +	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index, overlay_src_w,
> +		  overlay_src_h);
> +	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
> +		  overlay_src_x, overlay_src_y);
> +	igt_debug("Plane %d: on-crtc size %dx%d\n", index, overlay_crtc_w,
> +		  overlay_crtc_h);
> +	igt_debug("Plane %d: on-crtc position %dx%d\n", index, overlay_crtc_x,
> +		  overlay_crtc_y);
> +
> +	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
> +			 overlay_src_x, overlay_src_y, overlay_crtc_w,
> +			 overlay_crtc_h, overlay_crtc_x, overlay_crtc_y,
> +			 &pattern_fb);
> +
> +	/* Remove the original pattern framebuffer. */
> +	igt_remove_fb(data->drm_fd, &pattern_fb);
> +}
> +
> +static const char test_display_one_mode_desc[] =
> +	"Pick the first mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_one_mode(chamelium_data_t *data,
> +				  struct chamelium_port *port, uint32_t fourcc,
> +				  enum chamelium_check check, int count)
> +{
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	igt_require(igt_plane_has_format_mod(primary, fourcc,
> +					     DRM_FORMAT_MOD_LINEAR));
> +
> +	mode = &connector->modes[0];
> +	if (check == CHAMELIUM_CHECK_ANALOG) {
> +		bool bridge = chamelium_check_analog_bridge(data, port);
> +
> +		igt_assert(!(bridge && prune_vga_mode(data, mode)));
> +	}
> +
> +	do_test_display(data, port, output, mode, fourcc, check, count);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_all_modes_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then check captured frames are correct";
> +static void test_display_all_modes(chamelium_data_t *data,
> +				   struct chamelium_port *port, uint32_t fourcc,
> +				   enum chamelium_check check, int count)
> +{
> +	bool bridge;
> +	int i, count_modes;
> +
> +	if (check == CHAMELIUM_CHECK_ANALOG)
> +		bridge = chamelium_check_analog_bridge(data, port);
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		drmModeConnector *connector;
> +		drmModeModeInfo *mode;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +		igt_require(igt_plane_has_format_mod(primary, fourcc,
> +						     DRM_FORMAT_MOD_LINEAR));
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
> +		    prune_vga_mode(data, mode))
> +			continue;
> +
> +		do_test_display(data, port, output, mode, fourcc, check, count);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_frame_dump_desc[] =
> +	"For each mode of the IGT base EDID, display and capture a few "
> +	"frames, then download the captured frames and compare them "
> +	"bit-by-bit to the sent ones";
> +static void test_display_frame_dump(chamelium_data_t *data,
> +				    struct chamelium_port *port)
> +{
> +	int i, count_modes;
> +
> +	i = 0;
> +	do {
> +		igt_output_t *output;
> +		igt_plane_t *primary;
> +		struct igt_fb fb;
> +		struct chamelium_frame_dump *frame;
> +		drmModeModeInfo *mode;
> +		drmModeConnector *connector;
> +		int fb_id, j;
> +
> +		/*
> +		 * let's reset state each mode so we will get the
> +		 * HPD pulses realibably
> +		 */
> +		igt_modeset_disable_all_outputs(&data->display);
> +		chamelium_reset_state(&data->display, data->chamelium, port,
> +				      data->ports, data->port_count);
> +
> +		/*
> +		 * modes may change due to mode pruining and link issues, so we
> +		 * need to refresh the connector
> +		 */
> +		output = chamelium_prepare_output(data, port,
> +						  IGT_CUSTOM_EDID_BASE);
> +		connector = chamelium_port_get_connector(data->chamelium, port,
> +							 false);
> +		primary = igt_output_get_plane_type(output,
> +						    DRM_PLANE_TYPE_PRIMARY);
> +		igt_assert(primary);
> +
> +		/* we may skip some modes due to above but that's ok */
> +		count_modes = connector->count_modes;
> +		if (i >= count_modes)
> +			break;
> +
> +		mode = &connector->modes[i];
> +
> +		fb_id = igt_create_color_pattern_fb(
> +			data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +			&fb);
> +		igt_assert(fb_id > 0);
> +
> +		chamelium_enable_output(data, port, output, mode, &fb);
> +
> +		igt_debug("Reading frame dumps from Chamelium...\n");
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
> +		for (j = 0; j < 5; j++) {
> +			frame = chamelium_read_captured_frame(data->chamelium,
> +							      j);
> +			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
> +			chamelium_destroy_frame_dump(frame);
> +		}
> +
> +		igt_remove_fb(data->drm_fd, &fb);
> +		drmModeFreeConnector(connector);
> +	} while (++i < count_modes);
> +}
> +
> +static const char test_display_aspect_ratio_desc[] =
> +	"Pick a mode with a picture aspect-ratio, capture AVI InfoFrames and "
> +	"check they include the relevant fields";
> +static void test_display_aspect_ratio(chamelium_data_t *data,
> +				      struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	drmModeConnector *connector;
> +	drmModeModeInfo *mode;
> +	int fb_id, i;
> +	struct igt_fb fb;
> +	bool found, ok;
> +	struct chamelium_infoframe *infoframe;
> +	struct infoframe_avi infoframe_avi;
> +	uint8_t vic = 16; /* TODO: test more VICs */
> +	const struct vic_mode *vic_mode;
> +	uint32_t aspect_ratio;
> +	enum infoframe_avi_picture_aspect_ratio frame_ar;
> +
> +	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	output = chamelium_prepare_output(data, port,
> +					  IGT_CUSTOM_EDID_ASPECT_RATIO);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	vic_mode = &vic_modes[vic];
> +	aspect_ratio = vic_mode->picture_ar;
> +
> +	found = false;
> +	igt_assert(connector->count_modes > 0);
> +	for (i = 0; i < connector->count_modes; i++) {
> +		mode = &connector->modes[i];
> +
> +		if (vic_mode_matches_drm(vic_mode, mode)) {
> +			found = true;
> +			break;
> +		}
> +	}
> +	igt_assert_f(found,
> +		     "Failed to find mode with the correct aspect ratio\n");
> +
> +	fb_id = igt_create_color_pattern_fb(data->drm_fd, mode->hdisplay,
> +					    mode->vdisplay, DRM_FORMAT_XRGB8888,
> +					    DRM_FORMAT_MOD_LINEAR, 0, 0, 0,
> +					    &fb);
> +	igt_assert(fb_id > 0);
> +
> +	chamelium_enable_output(data, port, output, mode, &fb);
> +
> +	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
> +						 CHAMELIUM_INFOFRAME_AVI);
> +	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
> +
> +	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
> +				 infoframe->payload, infoframe->payload_size);
> +	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
> +
> +	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
> +
> +	igt_debug("Checking AVI InfoFrame\n");
> +	igt_debug("Picture aspect ratio: got %d, expected %d\n",
> +		  infoframe_avi.picture_aspect_ratio, frame_ar);
> +	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
> +		  infoframe_avi.vic, vic);
> +
> +	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
> +	igt_assert(infoframe_avi.vic == vic);
> +
> +	chamelium_infoframe_destroy(infoframe);
> +	igt_remove_fb(data->drm_fd, &fb);
> +	drmModeFreeConnector(connector);
> +}
> +
> +static const char test_display_planes_random_desc[] =
> +	"Setup a few overlay planes with random parameters, capture the frame "
> +	"and check it matches the expected output";
> +static void test_display_planes_random(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum chamelium_check check)
> +{
> +	igt_output_t *output;
> +	drmModeModeInfo *mode;
> +	igt_plane_t *primary_plane;
> +	struct igt_fb primary_fb;
> +	struct igt_fb result_fb;
> +	struct igt_fb *overlay_fbs;
> +	igt_crc_t *crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +	unsigned int overlay_planes_max = 0;
> +	unsigned int overlay_planes_count;
> +	cairo_surface_t *result_surface;
> +	int captured_frame_count;
> +	bool allow_scaling;
> +	bool allow_yuv;
> +	unsigned int i;
> +	unsigned int fb_id;
> +
> +	switch (check) {
> +	case CHAMELIUM_CHECK_CRC:
> +		allow_scaling = false;
> +		allow_yuv = false;
> +		break;
> +	case CHAMELIUM_CHECK_CHECKERBOARD:
> +		allow_scaling = true;
> +		allow_yuv = true;
> +		break;
> +	default:
> +		igt_assert(false);
> +	}
> +
> +	srand(time(NULL));
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Find the connector and pipe. */
> +	output = chamelium_prepare_output(data, port, IGT_CUSTOM_EDID_BASE);
> +
> +	mode = igt_output_get_mode(output);
> +
> +	/* Get a framebuffer for the primary plane. */
> +	primary_plane =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary_plane);
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
> +	igt_assert(fb_id > 0);
> +
> +	/* Get a framebuffer for the cairo composition result. */
> +	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> +			      DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
> +			      &result_fb);
> +	igt_assert(fb_id > 0);
> +
> +	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
> +
> +	/* Paint the primary framebuffer on the result surface. */
> +	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
> +			 &primary_fb);
> +
> +	/* Configure the primary plane. */
> +	igt_plane_set_fb(primary_plane, &primary_fb);
> +
> +	overlay_planes_max =
> +		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
> +
> +	/* Limit the number of planes to a reasonable scene. */
> +	overlay_planes_max = min(overlay_planes_max, 4u);
> +
> +	overlay_planes_count = (rand() % overlay_planes_max) + 1;
> +	igt_debug("Using %d overlay planes\n", overlay_planes_count);
> +
> +	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
> +
> +	for (i = 0; i < overlay_planes_count; i++) {
> +		struct igt_fb *overlay_fb = &overlay_fbs[i];
> +		igt_plane_t *plane = igt_output_get_plane_type_index(
> +			output, DRM_PLANE_TYPE_OVERLAY, i);
> +		igt_assert(plane);
> +
> +		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
> +					 result_surface, allow_scaling,
> +					 allow_yuv);
> +	}
> +
> +	cairo_surface_destroy(result_surface);
> +
> +	if (check == CHAMELIUM_CHECK_CRC)
> +		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&result_fb);
> +
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	if (check == CHAMELIUM_CHECK_CRC) {
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_count);
> +
> +		igt_assert(captured_frame_count == 1);
> +
> +		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
> +		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
> +						crc, &result_fb, 0);
> +
> +		free(expected_crc);
> +		free(crc);
> +	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
> +		struct chamelium_frame_dump *dump;
> +
> +		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
> +						  0, 0);
> +		chamelium_assert_frame_match_or_dump(data->chamelium, port,
> +						     dump, &result_fb, check);
> +		chamelium_destroy_frame_dump(dump);
> +	}
> +
> +	for (i = 0; i < overlay_planes_count; i++)
> +		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
> +
> +	free(overlay_fbs);
> +
> +	igt_remove_fb(data->drm_fd, &primary_fb);
> +	igt_remove_fb(data->drm_fd, &result_fb);
> +}
> +
> +IGT_TEST_DESCRIPTION("Tests requiring a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-single", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("dp-crc-fast", DisplayPort)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("dp-crc-multiple", DisplayPort)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("dp-frame-dump", DisplayPort)
> +			test_display_frame_dump(&data, port);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-single", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_subtest("hdmi-crc-fast", HDMIA)
> +			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
> +					      CHAMELIUM_CHECK_CRC, 1);
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("hdmi-crc-multiple", HDMIA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_CRC, 3);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-crc-nonplanar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CRC, 1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-crc-planes-random", HDMIA)
> +			test_display_planes_random(&data, port,
> +						   CHAMELIUM_CHECK_CRC);
> +
> +		igt_describe(test_display_one_mode_desc);
> +		connector_dynamic_subtest("hdmi-cmp-planar-formats", HDMIA)
> +		{
> +			int k;
> +			igt_output_t *output;
> +			igt_plane_t *primary;
> +
> +			output = chamelium_prepare_output(&data, port,
> +							  IGT_CUSTOM_EDID_BASE);
> +			primary = igt_output_get_plane_type(
> +				output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_assert(primary);
> +
> +			for (k = 0; k < primary->format_mod_count; k++) {
> +				if (!igt_fb_supported_format(
> +					    primary->formats[k]))
> +					continue;
> +
> +				if (!igt_format_is_yuv(primary->formats[k]))
> +					continue;
> +
> +				if (primary->modifiers[k] !=
> +				    DRM_FORMAT_MOD_LINEAR)
> +					continue;
> +
> +				igt_dynamic_f(
> +					"%s",
> +					igt_format_str(primary->formats[k]))
> +					test_display_one_mode(
> +						&data, port,
> +						primary->formats[k],
> +						CHAMELIUM_CHECK_CHECKERBOARD,
> +						1);
> +			}
> +		}
> +
> +		igt_describe(test_display_planes_random_desc);
> +		connector_subtest("hdmi-cmp-planes-random", HDMIA)
> +			test_display_planes_random(
> +				&data, port, CHAMELIUM_CHECK_CHECKERBOARD);
> +
> +		igt_describe(test_display_frame_dump_desc);
> +		connector_subtest("hdmi-frame-dump", HDMIA)
> +			test_display_frame_dump(&data, port);
> +
> +		igt_describe(test_display_aspect_ratio_desc);
> +		connector_subtest("hdmi-aspect-ratio", HDMIA)
> +			test_display_aspect_ratio(&data, port);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_display_all_modes_desc);
> +		connector_subtest("vga-frame-dump", VGA)
> +			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
> +					       CHAMELIUM_CHECK_ANALOG, 1);
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/chamelium/kms_chamelium_helper.c b/tests/chamelium/kms_chamelium_helper.c
> new file mode 100644
> index 00000000..b9544288
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.c
> @@ -0,0 +1,330 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "igt_edid.h"
> +#include "kms_chamelium_helper.h"
> +
> +void chamelium_init_test(chamelium_data_t *data)
> +{
> +	int i;
> +
> +	/* So fbcon doesn't try to reprobe things itself */
> +	kmstest_set_vt_graphics_mode();
> +
> +	data->drm_fd = drm_open_driver_master(DRIVER_ANY);
> +	igt_display_require(&data->display, data->drm_fd);
> +	igt_require(data->display.is_atomic);
> +
> +	/*
> +	 * XXX: disabling modeset, can be removed when
> +	 * igt_display_require will start doing this for us
> +	 */
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	/* we need to initalize chamelium after igt_display_require */
> +	data->chamelium = chamelium_init(data->drm_fd, &data->display);
> +	igt_require(data->chamelium);
> +
> +	data->ports = chamelium_get_ports(data->chamelium, &data->port_count);
> +
> +	for (i = 0; i < IGT_CUSTOM_EDID_COUNT; ++i) {
> +		data->edids[i] = chamelium_new_edid(data->chamelium,
> +						    igt_kms_get_custom_edid(i));
> +	}
> +}
> +
> +/* Wait for hotplug and return the remaining time left from timeout */
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout)
> +{
> +	struct timespec start, end;
> +	int elapsed;
> +	bool detected;
> +
> +	igt_assert_eq(igt_gettime(&start), 0);
> +	detected = igt_hotplug_detected(mon, *timeout);
> +	igt_assert_eq(igt_gettime(&end), 0);
> +
> +	elapsed = igt_time_elapsed(&start, &end);
> +	igt_assert_lte(0, elapsed);
> +	*timeout = max(0, *timeout - elapsed);
> +
> +	return detected;
> +}
> +
> +/**
> + * chamelium_wait_for_connector_after_hotplug:
> + *
> + * Waits for the connector attached to @port to have a status of @status after
> + * it's plugged/unplugged.
> + *
> + */
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status)
> +{
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int hotplug_count = 0;
> +
> +	igt_debug("Waiting for %s to get %s after a hotplug event...\n",
> +		  chamelium_port_get_name(port),
> +		  kmstest_connector_status_str(status));
> +
> +	while (timeout > 0) {
> +		if (!chamelium_wait_for_hotplug(mon, &timeout))
> +			break;
> +
> +		hotplug_count++;
> +
> +		if (chamelium_reprobe_connector(&data->display, data->chamelium,
> +						port) == status)
> +			return;
> +	}
> +
> +	igt_assert_f(
> +		false,
> +		"Timed out waiting for %s to get %s after a hotplug. Current state %s hotplug_count %d\n",
> +		chamelium_port_get_name(port),
> +		kmstest_connector_status_str(status),
> +		kmstest_connector_status_str(chamelium_reprobe_connector(
> +			&data->display, data->chamelium, port)),
> +		hotplug_count);
> +}
> +
> +/**
> + * chamelium_port_get_connector:
> + * @data: The Chamelium data instance to use
> + * @port: The chamelium port to prepare its connector
> + * @edid: The chamelium's default EDID has a lot of resolutions, way more then
> + * 		  we need to test. Additionally the default EDID doesn't support
> + *        HDMI audio.
> + *
> + * Makes sure the output display of the connector attached to @port is connected
> + * and ready for use.
> + *
> + * Returns: a pointer to the enabled igt_output_t
> + */
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid)
> +{
> +	igt_display_t *display = &data->display;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +
> +	/* The chamelium's default EDID has a lot of resolutions, way more then
> +	 * we need to test. Additionally the default EDID doesn't support HDMI
> +	 * audio.
> +	 */
> +	chamelium_set_edid(data, port, edid);
> +
> +	chamelium_plug(data->chamelium, port);
> +	chamelium_wait_for_conn_status_change(&data->display, data->chamelium,
> +					      port, DRM_MODE_CONNECTED);
> +
> +	igt_display_reset(display);
> +
> +	output = chamelium_get_output_for_port(data, port);
> +
> +	/* Refresh pipe to update connected status */
> +	igt_output_set_pipe(output, PIPE_NONE);
> +
> +	pipe = chamelium_get_pipe_for_output(display, output);
> +	igt_output_set_pipe(output, pipe);
> +
> +	return output;
> +}
> +
> +/**
> + * chamelium_enable_output:
> + *
> + * Modesets the connector attached to @port for the assigned @mode and draws the
> + * @fb.
> + *
> + */
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb)
> +{
> +	igt_display_t *display = output->display;
> +	igt_plane_t *primary =
> +		igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +
> +	igt_assert(primary);
> +
> +	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
> +	igt_plane_set_fb(primary, fb);
> +	igt_output_override_mode(output, mode);
> +
> +	/* Clear any color correction values that might be enabled */
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_DEGAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe,
> +					       IGT_CRTC_GAMMA_LUT, NULL, 0);
> +	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
> +		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM,
> +					       NULL, 0);
> +
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +
> +	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> +		usleep(250000);
> +
> +	drmModeFreeConnector(connector);
> +}
> +
> +/* Return pipe attached to @outpu.t */
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output)
> +{
> +	enum pipe pipe;
> +
> +	for_each_pipe(display, pipe) {
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			return pipe;
> +		}
> +	}
> +
> +	igt_assert_f(false, "No pipe found for output %s\n",
> +		     igt_output_name(output));
> +}
> +
> +static void chamelium_paint_xr24_pattern(uint32_t *data, size_t width,
> +					 size_t height, size_t stride,
> +					 size_t block_size)
> +{
> +	uint32_t colors[] = { 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff,
> +			      0xffffffff };
> +	unsigned i, j;
> +
> +	for (i = 0; i < height; i++)
> +		for (j = 0; j < width; j++)
> +			*(data + i * stride / 4 +
> +			  j) = colors[((j / block_size) + (i / block_size)) % 5];
> +}
> +
> +/**
> + * chamelium_get_pattern_fb:
> + *
> + * Creates an @fb with an xr24 pattern and returns the fb_id.
> + *
> + */
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb)
> +{
> +	int fb_id;
> +	void *ptr;
> +
> +	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
> +
> +	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
> +			      DRM_FORMAT_MOD_LINEAR, fb);
> +	igt_assert(fb_id > 0);
> +
> +	ptr = igt_fb_map_buffer(fb->fd, fb);
> +	igt_assert(ptr);
> +
> +	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
> +				     block_size);
> +	igt_fb_unmap_buffer(fb, ptr);
> +
> +	return fb_id;
> +}
> +
> +/* Generate a simple @fb for the size of @mode. */
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode)
> +{
> +	int fb_id;
> +
> +	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
> +					 DRM_FORMAT_XRGB8888, 64, fb);
> +
> +	igt_assert(fb_id > 0);
> +}
> +
> +/* Returns the first preferred mode for the connector attached to @port. */
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(chamelium, port, false);
> +	drmModeModeInfo mode;
> +	igt_assert(&connector->modes[0] != NULL);
> +	memcpy(&mode, &connector->modes[0], sizeof(mode));
> +	drmModeFreeConnector(connector);
> +	return mode;
> +}
> +
> +/* Returns the igt display output for the connector attached to @port. */
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port)
> +{
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, true);
> +	igt_output_t *output =
> +		igt_output_from_connector(&data->display, connector);
> +	drmModeFreeConnector(connector);
> +	igt_assert(output != NULL);
> +	return output;
> +}
> +
> +/* Set the EDID of index @edid to Chamelium's @port. */
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid)
> +{
> +	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
> +}
> +
> +/**
> + * chamelium_check_analog_bridge:
> + *
> + * Check if the connector associalted to @port is an analog bridge by checking
> + * if it has its own EDID.
> + *
> + */
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port)
> +{
> +	drmModePropertyBlobPtr edid_blob = NULL;
> +	drmModeConnector *connector =
> +		chamelium_port_get_connector(data->chamelium, port, false);
> +	uint64_t edid_blob_id;
> +	const struct edid *edid;
> +	char edid_vendor[3];
> +
> +	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
> +		drmModeFreeConnector(connector);
> +		return false;
> +	}
> +
> +	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
> +					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +					&edid_blob_id, NULL));
> +	igt_assert(edid_blob =
> +			   drmModeGetPropertyBlob(data->drm_fd, edid_blob_id));
> +
> +	edid = (const struct edid *)edid_blob->data;
> +	edid_get_mfg(edid, edid_vendor);
> +
> +	drmModeFreePropertyBlob(edid_blob);
> +	drmModeFreeConnector(connector);
> +
> +	/* Analog bridges provide their own EDID */
> +	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
> +	    edid_vendor[2] != 'T')
> +		return true;
> +
> +	return false;
> +}
> \ No newline at end of file
> diff --git a/tests/chamelium/kms_chamelium_helper.h b/tests/chamelium/kms_chamelium_helper.h
> new file mode 100644
> index 00000000..09fa4829
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_helper.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * A helper library for all Chamelium tests.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#ifndef TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +#define TESTS_CHAMELIUM_CHAMELIUM_HELPER_H
> +
> +#include "igt.h"
> +
> +#define ONLINE_TIMEOUT 20 /* seconds */
> +
> +#define for_each_port(p, port)                                 \
> +	for (p = 0, port = data.ports[p]; p < data.port_count; \
> +	     p++, port = data.ports[p])
> +
> +#define connector_subtest(name__, type__)                           \
> +	igt_subtest(name__)                                         \
> +	for_each_port(p, port) if (chamelium_port_get_type(port) == \
> +				   DRM_MODE_CONNECTOR_##type__)
> +
> +/*
> + * The chamelium data structure is used to store all the information known about
> + * chamelium to run the tests.
> + */
> +typedef struct {
> +	struct chamelium *chamelium;
> +	struct chamelium_port **ports;
> +	igt_display_t display;
> +	int port_count;
> +
> +	int drm_fd;
> +
> +	struct chamelium_edid *edids[IGT_CUSTOM_EDID_COUNT];
> +} chamelium_data_t;
> +
> +void chamelium_init_test(chamelium_data_t *data);
> +
> +bool chamelium_wait_for_hotplug(struct udev_monitor *mon, int *timeout);
> +void chamelium_wait_for_connector_after_hotplug(chamelium_data_t *data,
> +						struct udev_monitor *mon,
> +						struct chamelium_port *port,
> +						drmModeConnection status);
> +
> +igt_output_t *chamelium_prepare_output(chamelium_data_t *data,
> +				       struct chamelium_port *port,
> +				       enum igt_custom_edid_type edid);
> +void chamelium_enable_output(chamelium_data_t *data,
> +			     struct chamelium_port *port, igt_output_t *output,
> +			     drmModeModeInfo *mode, struct igt_fb *fb);
> +enum pipe chamelium_get_pipe_for_output(igt_display_t *display,
> +					igt_output_t *output);
> +
> +int chamelium_get_pattern_fb(chamelium_data_t *data, size_t width,
> +			     size_t height, uint32_t fourcc, size_t block_size,
> +			     struct igt_fb *fb);
> +void chamelium_create_fb_for_mode(chamelium_data_t *data, struct igt_fb *fb,
> +				  drmModeModeInfo *mode);
> +drmModeModeInfo chamelium_get_mode_for_port(struct chamelium *chamelium,
> +					    struct chamelium_port *port);
> +igt_output_t *chamelium_get_output_for_port(chamelium_data_t *data,
> +					    struct chamelium_port *port);
> +
> +void chamelium_set_edid(chamelium_data_t *data, struct chamelium_port *port,
> +			enum igt_custom_edid_type edid);
> +
> +bool chamelium_check_analog_bridge(chamelium_data_t *data,
> +				   struct chamelium_port *port);
> +
> +#endif /* TESTS_CHAMELIUM_CHAMELIUM_HELPER_H */
> diff --git a/tests/chamelium/kms_chamelium_hpd.c b/tests/chamelium/kms_chamelium_hpd.c
> new file mode 100644
> index 00000000..8a4e1aba
> --- /dev/null
> +++ b/tests/chamelium/kms_chamelium_hpd.c
> @@ -0,0 +1,512 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * A Chamelium test for testing the HPD functionality.
> + *
> + * Copyright 2022 Google LLC.
> + *
> + * Authors: Mark Yacoub <markyacoub@chromium.org>
> + */
> +
> +#include "kms_chamelium_helper.h"
> +
> +#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
> +#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
> +
> +#define HPD_TOGGLE_COUNT_VGA 5
> +#define HPD_TOGGLE_COUNT_DP_HDMI 15
> +#define HPD_TOGGLE_COUNT_FAST 3
> +
> +enum test_modeset_mode {
> +	TEST_MODESET_ON,
> +	TEST_MODESET_ON_OFF,
> +	TEST_MODESET_OFF,
> +};
> +
> +static void try_suspend_resume_hpd(chamelium_data_t *data,
> +				   struct chamelium_port *port,
> +				   enum igt_suspend_state state,
> +				   enum igt_suspend_test test,
> +				   struct udev_monitor *mon, bool connected)
> +{
> +	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
> +						     DRM_MODE_CONNECTED;
> +	int timeout = CHAMELIUM_HOTPLUG_TIMEOUT;
> +	int delay;
> +	int p;
> +
> +	igt_flush_uevents(mon);
> +
> +	delay = igt_get_autoresume_delay(state) * 1000 / 2;
> +
> +	if (port) {
> +		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
> +					      !connected);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			port = data->ports[p];
> +			chamelium_schedule_hpd_toggle(data->chamelium, port,
> +						      delay, !connected);
> +		}
> +
> +		port = NULL;
> +	}
> +
> +	igt_system_suspend_autoresume(state, test);
> +	igt_assert(chamelium_wait_for_hotplug(mon, &timeout));
> +	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
> +
> +	if (port) {
> +		igt_assert_eq(chamelium_reprobe_connector(
> +				      &data->display, data->chamelium, port),
> +			      target_state);
> +	} else {
> +		for (p = 0; p < data->port_count; p++) {
> +			drmModeConnection current_state;
> +
> +			port = data->ports[p];
> +			/*
> +			 * There could be as many hotplug events sent by
> +			 * driver as connectors we scheduled an HPD toggle on
> +			 * above, depending on timing. So if we're not seeing
> +			 * the expected connector state try to wait for an HPD
> +			 * event for each connector/port.
> +			 */
> +			current_state = chamelium_reprobe_connector(
> +				&data->display, data->chamelium, port);
> +			if (p > 0 && current_state != target_state) {
> +				igt_assert(chamelium_wait_for_hotplug(
> +					mon, &timeout));
> +				current_state = chamelium_reprobe_connector(
> +					&data->display, data->chamelium, port);
> +			}
> +
> +			igt_assert_eq(current_state, target_state);
> +		}
> +
> +		port = NULL;
> +	}
> +}
> +
> +static const char test_basic_hotplug_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug";
> +static void test_hotplug(chamelium_data_t *data, struct chamelium_port *port,
> +			 int toggle_count, enum test_modeset_mode modeset_mode)
> +{
> +	int i;
> +	enum pipe pipe;
> +	struct igt_fb fb = { 0 };
> +	drmModeModeInfo mode;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	igt_output_t *output = chamelium_get_output_for_port(data, port);
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +
> +	for (i = 0; i < toggle_count; i++) {
> +		igt_flush_uevents(mon);
> +
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF ||
> +		    (modeset_mode == TEST_MODESET_ON && i == 0)) {
> +			if (i == 0) {
> +				/* We can only get mode and pipe once we are
> +				 * connected */
> +				output = chamelium_get_output_for_port(data,
> +								       port);
> +				pipe = chamelium_get_pipe_for_output(
> +					&data->display, output);
> +				mode = chamelium_get_mode_for_port(
> +					data->chamelium, port);
> +				chamelium_create_fb_for_mode(data, &fb, &mode);
> +			}
> +
> +			igt_output_set_pipe(output, pipe);
> +			chamelium_enable_output(data, port, output, &mode, &fb);
> +		}
> +
> +		/* Now check if we get a hotplug from disconnection */
> +		chamelium_unplug(data->chamelium, port);
> +
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +
> +		igt_flush_uevents(mon);
> +
> +		if (modeset_mode == TEST_MODESET_ON_OFF) {
> +			igt_output_set_pipe(output, PIPE_NONE);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +	igt_remove_fb(data->drm_fd, &fb);
> +}
> +
> +static const char test_hotplug_for_each_pipe_desc[] =
> +	"Check that we get uevents and updated connector status on "
> +	"hotplug and unplug for each pipe with valid output";
> +static void test_hotplug_for_each_pipe(chamelium_data_t *data,
> +				       struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	enum pipe pipe;
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	/* Disconnect if any port got connected */
> +	chamelium_unplug(data->chamelium, port);
> +	chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +						   DRM_MODE_DISCONNECTED);
> +
> +	for_each_pipe(&data->display, pipe) {
> +		igt_flush_uevents(mon);
> +		/* Check if we get a sysfs hotplug event */
> +		chamelium_plug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(data, mon, port,
> +							   DRM_MODE_CONNECTED);
> +		igt_flush_uevents(mon);
> +		output = chamelium_get_output_for_port(data, port);
> +
> +		/* If pipe is valid for output then set it */
> +		if (igt_pipe_connector_valid(pipe, output)) {
> +			igt_output_set_pipe(output, pipe);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +		}
> +
> +		chamelium_unplug(data->chamelium, port);
> +		chamelium_wait_for_connector_after_hotplug(
> +			data, mon, port, DRM_MODE_DISCONNECTED);
> +		igt_flush_uevents(mon);
> +	}
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_suspend_resume_hpd_desc[] =
> +	"Toggle HPD during suspend, check that uevents are sent and connector "
> +	"status is updated";
> +static void test_suspend_resume_hpd(chamelium_data_t *data,
> +				    struct chamelium_port *port,
> +				    enum igt_suspend_state state,
> +				    enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, port, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_suspend_resume_hpd_common_desc[] =
> +	"Toggle HPD during suspend on all connectors, check that uevents are "
> +	"sent and connector status is updated";
> +static void test_suspend_resume_hpd_common(chamelium_data_t *data,
> +					   enum igt_suspend_state state,
> +					   enum igt_suspend_test test)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +	struct chamelium_port *port;
> +	int p;
> +
> +	for (p = 0; p < data->port_count; p++) {
> +		port = data->ports[p];
> +		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
> +	}
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, NULL,
> +			      data->ports, data->port_count);
> +
> +	/* Make sure we notice new connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
> +
> +	/* Now make sure we notice disconnected connectors after resuming */
> +	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_without_ddc_desc[] =
> +	"Disable DDC on a VGA connector, check we still get a uevent on hotplug";
> +static void test_hpd_without_ddc(chamelium_data_t *data,
> +				 struct chamelium_port *port)
> +{
> +	struct udev_monitor *mon = igt_watch_uevents();
> +
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +	igt_flush_uevents(mon);
> +
> +	/* Disable the DDC on the connector and make sure we still get a
> +	 * hotplug
> +	 */
> +	chamelium_port_set_ddc_state(data->chamelium, port, false);
> +	chamelium_plug(data->chamelium, port);
> +
> +	igt_assert(igt_hotplug_detected(mon, CHAMELIUM_HOTPLUG_TIMEOUT));
> +	igt_assert_eq(chamelium_reprobe_connector(&data->display,
> +						  data->chamelium, port),
> +		      DRM_MODE_CONNECTED);
> +
> +	igt_cleanup_uevents(mon);
> +}
> +
> +static const char test_hpd_storm_detect_desc[] =
> +	"Trigger a series of hotplugs in a very small timeframe to simulate a"
> +	"bad cable, check the kernel falls back to polling to avoid a hotplug "
> +	"storm";
> +static void test_hpd_storm_detect(chamelium_data_t *data,
> +				  struct chamelium_port *port, int width)
> +{
> +	struct udev_monitor *mon;
> +	int count = 0;
> +
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 1);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(igt_hpd_storm_detected(data->drm_fd));
> +
> +	mon = igt_watch_uevents();
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +
> +	/*
> +	 * Polling should have been enabled by the HPD storm at this point,
> +	 * so we should only get at most 1 hotplug event
> +	 */
> +	igt_until_timeout(5)
> +		count += igt_hotplug_detected(mon, 1);
> +	igt_assert_lt(count, 2);
> +
> +	igt_cleanup_uevents(mon);
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +static const char test_hpd_storm_disable_desc[] =
> +	"Disable HPD storm detection, trigger a storm and check the kernel "
> +	"doesn't detect one";
> +static void test_hpd_storm_disable(chamelium_data_t *data,
> +				   struct chamelium_port *port, int width)
> +{
> +	igt_require_hpd_storm_ctl(data->drm_fd);
> +	igt_modeset_disable_all_outputs(&data->display);
> +	chamelium_reset_state(&data->display, data->chamelium, port,
> +			      data->ports, data->port_count);
> +
> +	igt_hpd_storm_set_threshold(data->drm_fd, 0);
> +	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
> +	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
> +
> +	igt_hpd_storm_reset(data->drm_fd);
> +}
> +
> +IGT_TEST_DESCRIPTION("Testing HPD with a Chamelium board");
> +igt_main
> +{
> +	chamelium_data_t data;
> +	struct chamelium_port *port;
> +	int p;
> +
> +	igt_fixture {
> +		chamelium_init_test(&data);
> +	}
> +
> +	igt_describe("DisplayPort tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_DisplayPort,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-fast", DisplayPort) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-enable-disable-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("dp-hpd-with-enabled-mode", DisplayPort)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("dp-hpd-for-each-pipe", DisplayPort)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-suspend", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("dp-hpd-storm", DisplayPort)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_DP);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("dp-hpd-storm-disable", DisplayPort)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_DP);
> +	}
> +
> +	igt_describe("HDMI tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_HDMIA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_DP_HDMI,
> +				     TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-fast", HDMIA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-enable-disable-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("hdmi-hpd-with-enabled-mode", HDMIA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_hotplug_for_each_pipe_desc);
> +		connector_subtest("hdmi-hpd-for-each-pipe", HDMIA)
> +			test_hotplug_for_each_pipe(&data, port);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_storm_detect_desc);
> +		connector_subtest("hdmi-hpd-storm", HDMIA)
> +			test_hpd_storm_detect(&data, port,
> +					      HPD_STORM_PULSE_INTERVAL_HDMI);
> +
> +		igt_describe(test_hpd_storm_disable_desc);
> +		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
> +			test_hpd_storm_disable(&data, port,
> +					       HPD_STORM_PULSE_INTERVAL_HDMI);
> +	}
> +
> +	igt_describe("VGA tests");
> +	igt_subtest_group {
> +		igt_fixture {
> +			chamelium_require_connector_present(
> +				data.ports, DRM_MODE_CONNECTOR_VGA,
> +				data.port_count, 1);
> +		}
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_VGA, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-fast", VGA) test_hotplug(
> +			&data, port, HPD_TOGGLE_COUNT_FAST, TEST_MODESET_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-enable-disable-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON_OFF);
> +
> +		igt_describe(test_basic_hotplug_desc);
> +		connector_subtest("vga-hpd-with-enabled-mode", VGA)
> +			test_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST,
> +				     TEST_MODESET_ON);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-suspend", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_MEM,
> +						SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_desc);
> +		connector_subtest("vga-hpd-after-hibernate", VGA)
> +			test_suspend_resume_hpd(&data, port, SUSPEND_STATE_DISK,
> +						SUSPEND_TEST_DEVICES);
> +
> +		igt_describe(test_hpd_without_ddc_desc);
> +		connector_subtest("vga-hpd-without-ddc", VGA)
> +			test_hpd_without_ddc(&data, port);
> +	}
> +
> +	igt_describe("Tests that operate on all connectors");
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(data.port_count);
> +		}
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-suspend")
> +			test_suspend_resume_hpd_common(&data, SUSPEND_STATE_MEM,
> +						       SUSPEND_TEST_NONE);
> +
> +		igt_describe(test_suspend_resume_hpd_common_desc);
> +		igt_subtest("common-hpd-after-hibernate")
> +			test_suspend_resume_hpd_common(&data,
> +						       SUSPEND_STATE_DISK,
> +						       SUSPEND_TEST_DEVICES);
> +	}
> +
> +	igt_describe(test_hotplug_for_each_pipe_desc);
> +	connector_subtest("vga-hpd-for-each-pipe", VGA)
> +		test_hotplug_for_each_pipe(&data, port);
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
> index 0d307730..6e5cc436 100644
> --- a/tests/intel-ci/blacklist.txt
> +++ b/tests/intel-ci/blacklist.txt
> @@ -77,7 +77,7 @@ igt@kms_frontbuffer_tracking@.*drrs.*
>  # is too costly in comparison to the value
>  # provided.
>  ###############################################
> -igt@kms_chamelium@hdmi-.*-planes-random
> +igt@kms_chamelium_frames@hdmi-.*-planes-random
>  ###############################################
>  # Broadcom
>  ###############################################
> diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
> index f57f8ff3..fb4c0f73 100644
> --- a/tests/intel-ci/fast-feedback.testlist
> +++ b/tests/intel-ci/fast-feedback.testlist
> @@ -92,14 +92,14 @@ igt@kms_addfb_basic@unused-modifier
>  igt@kms_addfb_basic@unused-offsets
>  igt@kms_addfb_basic@unused-pitches
>  igt@kms_busy@basic
> -igt@kms_chamelium@dp-hpd-fast
> -igt@kms_chamelium@dp-edid-read
> -igt@kms_chamelium@dp-crc-fast
> -igt@kms_chamelium@hdmi-hpd-fast
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@vga-hpd-fast
> -igt@kms_chamelium@vga-edid-read
> +igt@kms_chamelium_hpd@dp-hpd-fast
> +igt@kms_chamelium_edid@dp-edid-read
> +igt@kms_chamelium_frames@dp-crc-fast
> +igt@kms_chamelium_hpd@hdmi-hpd-fast
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_hpd@vga-hpd-fast
> +igt@kms_chamelium_edid@vga-edid-read
>  igt@kms_prop_blob@basic
>  igt@kms_cursor_legacy@basic-busy-flip-before-cursor
>  igt@kms_cursor_legacy@basic-flip-after-cursor
> @@ -174,5 +174,5 @@ igt@i915_suspend@basic-s2idle-without-i915
>  igt@i915_suspend@basic-s3-without-i915
>  igt@gem_exec_suspend@basic-s0
>  igt@gem_exec_suspend@basic-s3
> -igt@kms_chamelium@common-hpd-after-suspend
> +igt@kms_chamelium_hpd@common-hpd-after-suspend
>  igt@kms_pipe_crc_basic@suspend-read-crc
> diff --git a/tests/kms_color_helper.h b/tests/kms_color_helper.h
> index f0ae30e3..f9242232 100644
> --- a/tests/kms_color_helper.h
> +++ b/tests/kms_color_helper.h
> @@ -27,7 +27,7 @@
>  
>  /*
>   * This header is for code that is shared between kms_color.c and
> - * kms_color_chamelium.c. Reusability elsewhere can be questionable.
> + * kms_chamelium_color.c. Reusability elsewhere can be questionable.
>   */
>  
>  #include <math.h>
> diff --git a/tests/meson.build b/tests/meson.build
> index 5c052e73..b52399d5 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -260,7 +260,10 @@ msm_progs = [
>  ]
>  
>  chamelium_progs = [
> -	'kms_chamelium',
> +	'kms_chamelium_audio',
> +	'kms_chamelium_edid',
> +	'kms_chamelium_frames',
> +	'kms_chamelium_hpd',
>  ]
>  
>  test_deps = [ igt_deps ]
> @@ -309,7 +312,8 @@ endforeach
>  if chamelium.found()
>  	foreach prog : chamelium_progs
>  		test_executables += executable(prog,
> -				 join_paths('chamelium', prog + '.c'),
> +				 [join_paths('chamelium', prog + '.c'), 
> +				 	join_paths('chamelium', 'kms_chamelium_helper.c')],
>  				 dependencies : test_deps,
>  				 install_dir : libexecdir,
>  				 install_rpath : libexecdir_rpathdir,
> @@ -436,13 +440,13 @@ test_executables += executable('kms_color',
>  test_list += 'kms_color'
>  
>  if chamelium.found()
> -       test_executables += executable('kms_color_chamelium',
> -                             [ 'chamelium/kms_color_chamelium.c', 'kms_color_helper.c' ],
> +       test_executables += executable('kms_chamelium_color',
> +                             [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
>                               dependencies : test_deps + [ chamelium ],
>                               install_dir : libexecdir,
>                               install_rpath : libexecdir_rpathdir,
>                               install : true)
> -       test_list += 'kms_color_chamelium'
> +       test_list += 'kms_chamelium_color'
>  endif
>  
>  test_executables += executable('sw_sync', 'sw_sync.c',
> diff --git a/tests/vc4_ci/vc4-chamelium-fast.testlist b/tests/vc4_ci/vc4-chamelium-fast.testlist
> index dd45d12a..a5521021 100644
> --- a/tests/vc4_ci/vc4-chamelium-fast.testlist
> +++ b/tests/vc4_ci/vc4-chamelium-fast.testlist
> @@ -1,14 +1,14 @@
> -igt@kms_chamelium@hdmi-crc-abgr8888
> -igt@kms_chamelium@hdmi-crc-argb1555
> -igt@kms_chamelium@hdmi-crc-argb8888
> -igt@kms_chamelium@hdmi-crc-bgr565
> -igt@kms_chamelium@hdmi-crc-bgr888
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@hdmi-crc-rgb565
> -igt@kms_chamelium@hdmi-crc-rgb888
> -igt@kms_chamelium@hdmi-crc-xbgr8888
> -igt@kms_chamelium@hdmi-crc-xrgb1555
> -igt@kms_chamelium@hdmi-crc-xrgb8888
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-hpd
> -igt@kms_chamelium@hdmi-hpd-fast
> +igt@kms_chamelium_frames@hdmi-crc-abgr8888
> +igt@kms_chamelium_frames@hdmi-crc-argb1555
> +igt@kms_chamelium_frames@hdmi-crc-argb8888
> +igt@kms_chamelium_frames@hdmi-crc-bgr565
> +igt@kms_chamelium_frames@hdmi-crc-bgr888
> +igt@kms_chamelium_frames@hdmi-crc-fast
> +igt@kms_chamelium_frames@hdmi-crc-rgb565
> +igt@kms_chamelium_frames@hdmi-crc-rgb888
> +igt@kms_chamelium_frames@hdmi-crc-xbgr8888
> +igt@kms_chamelium_frames@hdmi-crc-xrgb1555
> +igt@kms_chamelium_frames@hdmi-crc-xrgb8888
> +igt@kms_chamelium_edid@hdmi-edid-read
> +igt@kms_chamelium_hpd@hdmi-hpd
> +igt@kms_chamelium_hpd@hdmi-hpd-fast
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-12-07  0:14 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
@ 2022-12-07 12:59   ` Kamil Konieczny
  2022-12-07 14:55     ` Petri Latvala
  2022-12-08  4:54     ` Yedireswarapu, SaiX Nandan
  0 siblings, 2 replies; 25+ messages in thread
From: Kamil Konieczny @ 2022-12-07 12:59 UTC (permalink / raw)
  To: igt-dev; +Cc: Sai Nandan Yedireswarapu

Hi Sai,

On 2022-12-07 at 00:14:37 -0000, Patchwork wrote:
> == Series Details ==
> 
> Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
> URL   : https://patchwork.freedesktop.org/series/111501/
> State : failure
> 
> == Summary ==
> 
> CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208
> ====================================================
> 
> Summary
> -------
> 
>   **FAILURE**
> 
>   Serious unknown changes coming with IGTPW_8208 absolutely need to be
>   verified manually.
>   
>   If you think the reported changes have nothing to do with the changes
>   introduced in IGTPW_8208, please notify your bug team to allow them
>   to document this new failure mode, which will reduce false positives in CI.
> 
>   External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> 
> Participating hosts (30 -> 44)
> ------------------------------
> 
>   Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
>   Missing    (1): fi-cfl-8700k 
> 
> Possible new issues
> -------------------
> 
>   Here are the unknown changes that may have been introduced in IGTPW_8208:
> 
> ### IGT changes ###
> 
> #### Possible regressions ####
> 
>   * igt@i915_selftest@live@late_gt_pm:
>     - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
>    [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@late_gt_pm.html
> 

This i915_selftest is unrelated to changes in chamelium.

Below kms_chamelium_* tests should skip on all i915 HW.

Regards,
Kamil

>   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
>     - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
>    [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
>     - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
>    [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> 
>   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
>     - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
>    [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
>    [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
>    [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
>    [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_chamelium_edid@hdmi-edid-read.html
> 
>   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
>     - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
>    [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html
> 
>   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
>     - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
>    [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html
> 
>   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
>     - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
>    [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> 
>   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
>     - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
>    [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
>    [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
>    [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
>    [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
>    [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
>     - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
>    [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
>     - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
>    [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
>    [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
>    [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
>    [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
>    [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
>    [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
>    [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
>    [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> 
>   
> New tests
> ---------
> 
>   New tests have been introduced between CI_DRM_12475 and IGTPW_8208:
> 
> ### New IGT tests (9) ###
> 
>   * igt@kms_chamelium_edid@dp-edid-read:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_edid@hdmi-edid-read:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_edid@vga-edid-read:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_frames@dp-crc-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_frames@hdmi-crc-fast:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@common-hpd-after-suspend:
>     - Statuses : 1 pass(s) 33 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@dp-hpd-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@hdmi-hpd-fast:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@vga-hpd-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   
> 
> Known issues
> ------------
> 
>   Here are the changes found in IGTPW_8208 that come from known issues:
> 
> ### IGT changes ###
> 
> #### Issues hit ####
> 
>   * igt@debugfs_test@basic-hwmon:
>     - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
>    [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@debugfs_test@basic-hwmon.html
> 
>   * igt@gem_exec_gttfill@basic:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
>    [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
>     - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
>    [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
>    [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> 
>   * igt@gem_huc_copy@huc-copy:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
>    [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html
> 
>   * igt@gem_lmem_swapping@basic:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
>    [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html
> 
>   * igt@gem_lmem_swapping@parallel-random-engines:
>     - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
>    [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
>    [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html
> 
>   * igt@gem_mmap@basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
>    [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
>    [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_mmap@basic.html
> 
>   * igt@gem_render_tiled_blits@basic:
>     - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
>    [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_render_tiled_blits@basic.html
> 
>   * igt@gem_tiled_blits@basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
>    [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_blits@basic.html
> 
>   * igt@gem_tiled_fence_blits@basic:
>     - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
>    [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html
> 
>   * igt@gem_tiled_pread_basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
>    [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
>    [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_tiled_pread_basic.html
> 
>   * igt@i915_module_load@load:
>     - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
>    [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i915_module_load@load.html
> 
>   * igt@i915_pm_backlight@basic-brightness:
>     - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
>    [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
>    [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html
> 
>   * igt@i915_pm_rps@basic-api:
>     - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
>    [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
>    [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
>    [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_rps@basic-api.html
> 
>   * igt@i915_selftest@live@gt_heartbeat:
>     - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
>    [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
>    [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> 
>   * igt@i915_selftest@live@gt_mocs:
>     - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
>    [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
>    [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> 
>   * igt@i915_selftest@live@gt_pm:
>     - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
>    [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html
> 
>   * igt@kms_addfb_basic@basic-x-tiled-legacy:
>     - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
>    [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html
> 
>   * igt@kms_addfb_basic@basic-y-tiled-legacy:
>     - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
>    [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
>    [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> 
>   * igt@kms_addfb_basic@tile-pitch-mismatch:
>     - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
>    [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html
> 
>   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
>     - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
>    [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html
> 
>   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
>     - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
>    [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html
> 
>   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
>     - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
>    [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html
> 
>   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
>     - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
>    [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
>     - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
>    [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
>     - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
>    [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html
> 
>   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
>     - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
>    [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
>     - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
>    [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> 
>   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
>     - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
>    [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
>     - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
>    [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
>     - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
>    [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
>     - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
>    [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
>    [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
>    [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
>    [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
>    [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
>    [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
>    [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html
> 
>   * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
>     - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
>    [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
>    [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
>    [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> 
>   * igt@kms_force_connector_basic@force-load-detect:
>     - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
>    [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
>    [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
>    [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html
> 
>   * igt@kms_pipe_crc_basic@suspend-read-crc:
>     - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
>    [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html
> 
>   * igt@kms_psr@primary_page_flip:
>     - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
>    [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_psr@primary_page_flip.html
> 
>   * igt@kms_psr@sprite_plane_onoff:
>     - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
>    [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html
> 
>   * igt@kms_setmode@basic-clone-single-crtc:
>     - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
>    [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
>    [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
>    [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html
> 
>   * igt@prime_vgem@basic-fence-read:
>     - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
>    [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-fence-read.html
> 
>   * igt@prime_vgem@basic-gtt:
>     - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
>    [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
>    [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-gtt.html
> 
>   * igt@prime_vgem@basic-userptr:
>     - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
>    [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
>    [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
>    [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-userptr.html
> 
>   * igt@prime_vgem@basic-write:
>     - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
>    [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
>    [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-write.html
> 
>   * igt@runner@aborted:
>     - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
>    [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@runner@aborted.html
> 
>   
> #### Possible fixes ####
> 
>   * igt@gem_exec_suspend@basic-s3@smem:
>     - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
>    [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
>    [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> 
>   
>   {name}: This element is suppressed. This means it is ignored when computing
>           the status of the difference (SUCCESS, WARNING, or FAILURE).
> 
>   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
>   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
>   [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
>   [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
>   [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
>   [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
>   [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
>   [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
>   [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
>   [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
>   [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
>   [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
>   [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
>   [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
>   [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
>   [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
>   [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
>   [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
>   [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
>   [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
>   [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
>   [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
>   [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
>   [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
>   [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
>   [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
>   [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
>   [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
>   [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
>   [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
>   [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
>   [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
>   [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
>   [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
>   [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
>   [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
>   [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
>   [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
>   [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
>   [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
>   [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
>   [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
>   [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
>   [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
>   [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
>   [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
>   [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
>   [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
>   [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
>   [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
>   [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
>   [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
> 
> 
> Build changes
> -------------
> 
>   * CI: CI-20190529 -> None
>   * IGT: IGT_7084 -> IGTPW_8208
> 
>   CI-20190529: 20190529
>   CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
>   IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
>   IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
> 
> == Logs ==
> 
> For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-12-07 12:59   ` Kamil Konieczny
@ 2022-12-07 14:55     ` Petri Latvala
  2022-12-08  4:55       ` Yedireswarapu, SaiX Nandan
  2022-12-08  4:54     ` Yedireswarapu, SaiX Nandan
  1 sibling, 1 reply; 25+ messages in thread
From: Petri Latvala @ 2022-12-07 14:55 UTC (permalink / raw)
  To: Kamil Konieczny, igt-dev, Sai Nandan Yedireswarapu

On Wed, Dec 07, 2022 at 01:59:03PM +0100, Kamil Konieczny wrote:
> Hi Sai,
> 
> On 2022-12-07 at 00:14:37 -0000, Patchwork wrote:
> > == Series Details ==
> > 
> > Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
> > URL   : https://patchwork.freedesktop.org/series/111501/
> > State : failure
> > 
> > == Summary ==
> > 
> > CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208
> > ====================================================
> > 
> > Summary
> > -------
> > 
> >   **FAILURE**
> > 
> >   Serious unknown changes coming with IGTPW_8208 absolutely need to be
> >   verified manually.
> >   
> >   If you think the reported changes have nothing to do with the changes
> >   introduced in IGTPW_8208, please notify your bug team to allow them
> >   to document this new failure mode, which will reduce false positives in CI.
> > 
> >   External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> > 
> > Participating hosts (30 -> 44)
> > ------------------------------
> > 
> >   Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
> >   Missing    (1): fi-cfl-8700k 
> > 
> > Possible new issues
> > -------------------
> > 
> >   Here are the unknown changes that may have been introduced in IGTPW_8208:
> > 
> > ### IGT changes ###
> > 
> > #### Possible regressions ####
> > 
> >   * igt@i915_selftest@live@late_gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
> >    [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@late_gt_pm.html
> > 
> 
> This i915_selftest is unrelated to changes in chamelium.
> 
> Below kms_chamelium_* tests should skip on all i915 HW.

For new tests filters can be added/modified when the results appear in
postmerge.

We have some chamelium hosts in BAT so it's not all i915 HW. But the
existing chamelium-skip filter is the one where these new test names
can be added.


-- 
Petri Latvala



> 
> Regards,
> Kamil
> 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
> >    [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> >     - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
> >    [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
> >    [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
> >    [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
> >    [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
> >    [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
> >    [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
> >    [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
> >    [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
> >    [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
> >    [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
> >    [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
> >    [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
> >    [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
> >    [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
> >    [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
> >    [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
> >    [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
> >    [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
> >    [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
> >    [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
> >    [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
> >    [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   
> > New tests
> > ---------
> > 
> >   New tests have been introduced between CI_DRM_12475 and IGTPW_8208:
> > 
> > ### New IGT tests (9) ###
> > 
> >   * igt@kms_chamelium_edid@dp-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@hdmi-edid-read:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@vga-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@dp-crc-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@hdmi-crc-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@common-hpd-after-suspend:
> >     - Statuses : 1 pass(s) 33 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@dp-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@hdmi-hpd-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@vga-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   
> > 
> > Known issues
> > ------------
> > 
> >   Here are the changes found in IGTPW_8208 that come from known issues:
> > 
> > ### IGT changes ###
> > 
> > #### Issues hit ####
> > 
> >   * igt@debugfs_test@basic-hwmon:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
> >    [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@debugfs_test@basic-hwmon.html
> > 
> >   * igt@gem_exec_gttfill@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
> >    [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
> >     - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
> >    [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> >    [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> > 
> >   * igt@gem_huc_copy@huc-copy:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
> >    [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html
> > 
> >   * igt@gem_lmem_swapping@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
> >    [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html
> > 
> >   * igt@gem_lmem_swapping@parallel-random-engines:
> >     - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
> >    [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
> >    [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html
> > 
> >   * igt@gem_mmap@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
> >    [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
> >    [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_mmap@basic.html
> > 
> >   * igt@gem_render_tiled_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
> >    [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_render_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_blits@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
> >    [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_fence_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
> >    [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html
> > 
> >   * igt@gem_tiled_pread_basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
> >    [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
> >    [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_tiled_pread_basic.html
> > 
> >   * igt@i915_module_load@load:
> >     - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
> >    [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i915_module_load@load.html
> > 
> >   * igt@i915_pm_backlight@basic-brightness:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
> >    [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
> >    [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html
> > 
> >   * igt@i915_pm_rps@basic-api:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
> >    [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
> >    [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
> >    [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_rps@basic-api.html
> > 
> >   * igt@i915_selftest@live@gt_heartbeat:
> >     - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
> >    [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> >    [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> > 
> >   * igt@i915_selftest@live@gt_mocs:
> >     - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
> >    [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> >    [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> > 
> >   * igt@i915_selftest@live@gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
> >    [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html
> > 
> >   * igt@kms_addfb_basic@basic-x-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
> >    [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@basic-y-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
> >    [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
> >    [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@tile-pitch-mismatch:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
> >    [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html
> > 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
> >    [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
> >    [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
> >    [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
> >    [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
> >    [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
> >    [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
> >    [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> >     - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
> >    [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
> >    [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
> >    [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> >     - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
> >    [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
> >    [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
> >    [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
> >    [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
> >    [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
> >    [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
> >    [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
> >    [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
> >    [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
> >    [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
> >    [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> > 
> >   * igt@kms_force_connector_basic@force-load-detect:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
> >    [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
> >    [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
> >    [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html
> > 
> >   * igt@kms_pipe_crc_basic@suspend-read-crc:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
> >    [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html
> > 
> >   * igt@kms_psr@primary_page_flip:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_psr@primary_page_flip.html
> > 
> >   * igt@kms_psr@sprite_plane_onoff:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html
> > 
> >   * igt@kms_setmode@basic-clone-single-crtc:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
> >    [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
> >    [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
> >    [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html
> > 
> >   * igt@prime_vgem@basic-fence-read:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
> >    [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-fence-read.html
> > 
> >   * igt@prime_vgem@basic-gtt:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-gtt.html
> > 
> >   * igt@prime_vgem@basic-userptr:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
> >    [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
> >    [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
> >    [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-userptr.html
> > 
> >   * igt@prime_vgem@basic-write:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
> >    [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
> >    [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-write.html
> > 
> >   * igt@runner@aborted:
> >     - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
> >    [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@runner@aborted.html
> > 
> >   
> > #### Possible fixes ####
> > 
> >   * igt@gem_exec_suspend@basic-s3@smem:
> >     - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
> >    [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> >    [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> > 
> >   
> >   {name}: This element is suppressed. This means it is ignored when computing
> >           the status of the difference (SUCCESS, WARNING, or FAILURE).
> > 
> >   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
> >   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
> >   [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
> >   [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
> >   [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
> >   [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
> >   [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
> >   [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
> >   [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
> >   [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
> >   [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
> >   [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
> >   [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
> >   [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
> >   [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
> >   [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
> >   [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
> >   [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
> >   [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
> >   [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
> >   [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
> >   [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
> >   [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
> >   [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
> >   [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
> >   [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
> >   [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
> >   [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
> >   [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
> >   [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
> >   [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
> >   [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
> >   [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
> >   [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
> >   [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
> >   [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
> >   [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
> >   [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
> >   [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
> >   [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
> >   [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
> >   [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
> >   [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
> >   [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
> >   [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
> >   [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
> >   [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
> >   [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
> >   [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
> >   [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
> >   [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
> >   [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
> > 
> > 
> > Build changes
> > -------------
> > 
> >   * CI: CI-20190529 -> None
> >   * IGT: IGT_7084 -> IGTPW_8208
> > 
> >   CI-20190529: 20190529
> >   CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
> >   IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> >   IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
> > 
> > == Logs ==
> > 
> > For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-12-07 12:59   ` Kamil Konieczny
  2022-12-07 14:55     ` Petri Latvala
@ 2022-12-08  4:54     ` Yedireswarapu, SaiX Nandan
  1 sibling, 0 replies; 25+ messages in thread
From: Yedireswarapu, SaiX Nandan @ 2022-12-08  4:54 UTC (permalink / raw)
  To: Kamil Konieczny, igt-dev

Hi,

Will address possible regressions and update here shortly.

Thanks,
Y Sai Nandan


-----Original Message-----
From: Kamil Konieczny <kamil.konieczny@linux.intel.com> 
Sent: Wednesday, December 7, 2022 6:29 PM
To: igt-dev@lists.freedesktop.org
Cc: Yedireswarapu, SaiX Nandan <saix.nandan.yedireswarapu@intel.com>
Subject: Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)

Hi Sai,

On 2022-12-07 at 00:14:37 -0000, Patchwork wrote:
> == Series Details ==
> 
> Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
> URL   : https://patchwork.freedesktop.org/series/111501/
> State : failure
> 
> == Summary ==
> 
> CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208 
> ====================================================
> 
> Summary
> -------
> 
>   **FAILURE**
> 
>   Serious unknown changes coming with IGTPW_8208 absolutely need to be
>   verified manually.
>   
>   If you think the reported changes have nothing to do with the changes
>   introduced in IGTPW_8208, please notify your bug team to allow them
>   to document this new failure mode, which will reduce false positives in CI.
> 
>   External URL: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> 
> Participating hosts (30 -> 44)
> ------------------------------
> 
>   Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
>   Missing    (1): fi-cfl-8700k 
> 
> Possible new issues
> -------------------
> 
>   Here are the unknown changes that may have been introduced in IGTPW_8208:
> 
> ### IGT changes ###
> 
> #### Possible regressions ####
> 
>   * igt@i915_selftest@live@late_gt_pm:
>     - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
>    [1]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@
> i915_selftest@live@late_gt_pm.html
> 

This i915_selftest is unrelated to changes in chamelium.

Below kms_chamelium_* tests should skip on all i915 HW.

Regards,
Kamil

>   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
>     - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
>    [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
>     - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
>    [3]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_c
> hamelium_edid@dp-edid-read.html
> 
>   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
>     - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
>    [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
>    [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
>    [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
>    [7]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> chamelium_edid@hdmi-edid-read.html
> 
>   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
>     - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
>    [8]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms
> _chamelium_frames@dp-crc-fast.html
> 
>   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
>     - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
>    [9]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms
> _chamelium_frames@hdmi-crc-fast.html
> 
>   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
>     - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
>    [10]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms
> _chamelium_hpd@common-hpd-after-suspend.html
> 
>   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
>     - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
>    [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
>    [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
>    [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
>    [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
>     - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
>    [15]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_
> chamelium_hpd@dp-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
>     - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
>    [16]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms
> _chamelium_hpd@hdmi-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
>     - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
>    [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
>    [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
>    [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
>    [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
>    [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
>    [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
>    [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
>    [24]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms
> _chamelium_hpd@vga-hpd-fast.html
> 
>   
> New tests
> ---------
> 
>   New tests have been introduced between CI_DRM_12475 and IGTPW_8208:
> 
> ### New IGT tests (9) ###
> 
>   * igt@kms_chamelium_edid@dp-edid-read:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_edid@hdmi-edid-read:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_edid@vga-edid-read:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_frames@dp-crc-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_frames@hdmi-crc-fast:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@common-hpd-after-suspend:
>     - Statuses : 1 pass(s) 33 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@dp-hpd-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@hdmi-hpd-fast:
>     - Statuses : 1 pass(s) 42 skip(s)
>     - Exec time: [0.0] s
> 
>   * igt@kms_chamelium_hpd@vga-hpd-fast:
>     - Statuses : 43 skip(s)
>     - Exec time: [0.0] s
> 
>   
> 
> Known issues
> ------------
> 
>   Here are the changes found in IGTPW_8208 that come from known issues:
> 
> ### IGT changes ###
> 
> #### Issues hit ####
> 
>   * igt@debugfs_test@basic-hwmon:
>     - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
>    [25]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@deb
> ugfs_test@basic-hwmon.html
> 
>   * igt@gem_exec_gttfill@basic:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
>    [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
>     - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
>    [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
>    [28]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@ge
> m_exec_gttfill@basic.html
> 
>   * igt@gem_huc_copy@huc-copy:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
>    [29]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@
> gem_huc_copy@huc-copy.html
> 
>   * igt@gem_lmem_swapping@basic:
>     - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
>    [30]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@
> gem_lmem_swapping@basic.html
> 
>   * igt@gem_lmem_swapping@parallel-random-engines:
>     - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
>    [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
>    [32]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem
> _lmem_swapping@parallel-random-engines.html
> 
>   * igt@gem_mmap@basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
>    [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
>    [34]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_
> mmap@basic.html
> 
>   * igt@gem_render_tiled_blits@basic:
>     - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
>    [35]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_
> render_tiled_blits@basic.html
> 
>   * igt@gem_tiled_blits@basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
>    [36]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_
> tiled_blits@basic.html
> 
>   * igt@gem_tiled_fence_blits@basic:
>     - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
>    [37]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_
> tiled_fence_blits@basic.html
> 
>   * igt@gem_tiled_pread_basic:
>     - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
>    [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
>    [39]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem
> _tiled_pread_basic.html
> 
>   * igt@i915_module_load@load:
>     - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
>    [40]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i
> 915_module_load@load.html
> 
>   * igt@i915_pm_backlight@basic-brightness:
>     - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
>    [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
>    [42]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915
> _pm_backlight@basic-brightness.html
> 
>   * igt@i915_pm_rps@basic-api:
>     - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
>    [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
>    [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
>    [45]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915
> _pm_rps@basic-api.html
> 
>   * igt@i915_selftest@live@gt_heartbeat:
>     - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
>    [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
>    [47]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i
> 915_selftest@live@gt_heartbeat.html
> 
>   * igt@i915_selftest@live@gt_mocs:
>     - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
>    [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
>    [49]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i91
> 5_selftest@live@gt_mocs.html
> 
>   * igt@i915_selftest@live@gt_pm:
>     - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
>    [50]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@
> i915_selftest@live@gt_pm.html
> 
>   * igt@kms_addfb_basic@basic-x-tiled-legacy:
>     - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
>    [51]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_
> addfb_basic@basic-x-tiled-legacy.html
> 
>   * igt@kms_addfb_basic@basic-y-tiled-legacy:
>     - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
>    [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
>    [53]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> addfb_basic@basic-y-tiled-legacy.html
> 
>   * igt@kms_addfb_basic@tile-pitch-mismatch:
>     - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
>    [54]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> addfb_basic@tile-pitch-mismatch.html
> 
>   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
>     - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
>    [55]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@km
> s_chamelium_edid@dp-edid-read.html
> 
>   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
>     - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
>    [56]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms
> _chamelium_edid@hdmi-edid-read.html
> 
>   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
>     - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
>    [57]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms
> _chamelium_frames@dp-crc-fast.html
> 
>   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
>     - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
>    [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
>     - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
>    [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
>     - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
>    [60]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@k
> ms_chamelium_frames@hdmi-crc-fast.html
> 
>   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
>     - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
>    [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
>     - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
>    [62]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@km
> s_chamelium_hpd@common-hpd-after-suspend.html
> 
>   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
>     - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
>    [63]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@
> kms_chamelium_hpd@dp-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
>     - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
>    [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
>     - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
>    [65]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_
> chamelium_hpd@hdmi-hpd-fast.html
> 
>   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
>     - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
>    [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
>    [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
>    [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
>    [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
>    [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
>    [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
>     - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
>    [72]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@k
> ms_chamelium_hpd@vga-hpd-fast.html
> 
>   * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
>     - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
>    [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
>    [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
>    [75]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> cursor_legacy@basic-busy-flip-before-cursor.html
> 
>   * igt@kms_force_connector_basic@force-load-detect:
>     - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
>    [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
>    [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
>    [78]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> force_connector_basic@force-load-detect.html
> 
>   * igt@kms_pipe_crc_basic@suspend-read-crc:
>     - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
>    [79]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms
> _pipe_crc_basic@suspend-read-crc.html
> 
>   * igt@kms_psr@primary_page_flip:
>     - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
>    [80]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_
> psr@primary_page_flip.html
> 
>   * igt@kms_psr@sprite_plane_onoff:
>     - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
>    [81]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_
> psr@sprite_plane_onoff.html
> 
>   * igt@kms_setmode@basic-clone-single-crtc:
>     - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
>    [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
>     - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
>    [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
>    [84]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms
> _setmode@basic-clone-single-crtc.html
> 
>   * igt@prime_vgem@basic-fence-read:
>     - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
>    [85]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prim
> e_vgem@basic-fence-read.html
> 
>   * igt@prime_vgem@basic-gtt:
>     - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
>    [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
>    [87]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prim
> e_vgem@basic-gtt.html
> 
>   * igt@prime_vgem@basic-userptr:
>     - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
>    [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
>    [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
>     - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
>    [90]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prim
> e_vgem@basic-userptr.html
> 
>   * igt@prime_vgem@basic-write:
>     - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
>    [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
>     - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
>    [92]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@pri
> me_vgem@basic-write.html
> 
>   * igt@runner@aborted:
>     - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
>    [93]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@r
> unner@aborted.html
> 
>   
> #### Possible fixes ####
> 
>   * igt@gem_exec_suspend@basic-s3@smem:
>     - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
>    [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
>    [95]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem
> _exec_suspend@basic-s3@smem.html
> 
>   
>   {name}: This element is suppressed. This means it is ignored when computing
>           the status of the difference (SUCCESS, WARNING, or FAILURE).
> 
>   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
>   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
>   [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
>   [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
>   [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
>   [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
>   [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
>   [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
>   [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
>   [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
>   [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
>   [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
>   [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
>   [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
>   [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
>   [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
>   [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
>   [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
>   [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
>   [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
>   [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
>   [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
>   [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
>   [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
>   [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
>   [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
>   [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
>   [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
>   [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
>   [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
>   [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
>   [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
>   [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
>   [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
>   [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
>   [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
>   [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
>   [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
>   [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
>   [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
>   [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
>   [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
>   [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
>   [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
>   [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
>   [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
>   [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
>   [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
>   [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
>   [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
>   [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
>   [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
> 
> 
> Build changes
> -------------
> 
>   * CI: CI-20190529 -> None
>   * IGT: IGT_7084 -> IGTPW_8208
> 
>   CI-20190529: 20190529
>   CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
>   IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
>   IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ 
> https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
> 
> == Logs ==
> 
> For more details see: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-12-07 14:55     ` Petri Latvala
@ 2022-12-08  4:55       ` Yedireswarapu, SaiX Nandan
  2022-12-08  6:37         ` Yedireswarapu, SaiX Nandan
  0 siblings, 1 reply; 25+ messages in thread
From: Yedireswarapu, SaiX Nandan @ 2022-12-08  4:55 UTC (permalink / raw)
  To: Latvala, Petri, Kamil Konieczny, igt-dev

Hi,

Will address possible regressions and update here shortly.

Thanks,
Y Sai Nandan

-----Original Message-----
From: Latvala, Petri <petri.latvala@intel.com> 
Sent: Wednesday, December 7, 2022 8:25 PM
To: Kamil Konieczny <kamil.konieczny@linux.intel.com>; igt-dev@lists.freedesktop.org; Yedireswarapu, SaiX Nandan <saix.nandan.yedireswarapu@intel.com>
Subject: Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)

On Wed, Dec 07, 2022 at 01:59:03PM +0100, Kamil Konieczny wrote:
> Hi Sai,
> 
> On 2022-12-07 at 00:14:37 -0000, Patchwork wrote:
> > == Series Details ==
> > 
> > Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
> > URL   : https://patchwork.freedesktop.org/series/111501/
> > State : failure
> > 
> > == Summary ==
> > 
> > CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208 
> > ====================================================
> > 
> > Summary
> > -------
> > 
> >   **FAILURE**
> > 
> >   Serious unknown changes coming with IGTPW_8208 absolutely need to be
> >   verified manually.
> >   
> >   If you think the reported changes have nothing to do with the changes
> >   introduced in IGTPW_8208, please notify your bug team to allow them
> >   to document this new failure mode, which will reduce false positives in CI.
> > 
> >   External URL: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> > 
> > Participating hosts (30 -> 44)
> > ------------------------------
> > 
> >   Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
> >   Missing    (1): fi-cfl-8700k 
> > 
> > Possible new issues
> > -------------------
> > 
> >   Here are the unknown changes that may have been introduced in IGTPW_8208:
> > 
> > ### IGT changes ###
> > 
> > #### Possible regressions ####
> > 
> >   * igt@i915_selftest@live@late_gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
> >    [1]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/ig
> > t@i915_selftest@live@late_gt_pm.html
> > 
> 
> This i915_selftest is unrelated to changes in chamelium.
> 
> Below kms_chamelium_* tests should skip on all i915 HW.

For new tests filters can be added/modified when the results appear in postmerge.

We have some chamelium hosts in BAT so it's not all i915 HW. But the existing chamelium-skip filter is the one where these new test names can be added.


--
Petri Latvala



> 
> Regards,
> Kamil
> 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
> >    [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> >     - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
> >    [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
> >    [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
> >    [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
> >    [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
> >    [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
> >    [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
> >    [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
> >    [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
> >    [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
> >    [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
> >    [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
> >    [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
> >    [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
> >    [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
> >    [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
> >    [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
> >    [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
> >    [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
> >    [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
> >    [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
> >    [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
> >    [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   
> > New tests
> > ---------
> > 
> >   New tests have been introduced between CI_DRM_12475 and IGTPW_8208:
> > 
> > ### New IGT tests (9) ###
> > 
> >   * igt@kms_chamelium_edid@dp-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@hdmi-edid-read:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@vga-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@dp-crc-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@hdmi-crc-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@common-hpd-after-suspend:
> >     - Statuses : 1 pass(s) 33 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@dp-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@hdmi-hpd-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@vga-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   
> > 
> > Known issues
> > ------------
> > 
> >   Here are the changes found in IGTPW_8208 that come from known issues:
> > 
> > ### IGT changes ###
> > 
> > #### Issues hit ####
> > 
> >   * igt@debugfs_test@basic-hwmon:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
> >    [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@debugfs_test@basic-hwmon.html
> > 
> >   * igt@gem_exec_gttfill@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
> >    [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
> >     - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
> >    [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> >    [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> > 
> >   * igt@gem_huc_copy@huc-copy:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
> >    [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html
> > 
> >   * igt@gem_lmem_swapping@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
> >    [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html
> > 
> >   * igt@gem_lmem_swapping@parallel-random-engines:
> >     - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
> >    [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
> >    [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html
> > 
> >   * igt@gem_mmap@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
> >    [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
> >    [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_mmap@basic.html
> > 
> >   * igt@gem_render_tiled_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
> >    [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_render_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_blits@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
> >    [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_fence_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
> >    [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html
> > 
> >   * igt@gem_tiled_pread_basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
> >    [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
> >    [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_tiled_pread_basic.html
> > 
> >   * igt@i915_module_load@load:
> >     - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
> >    [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i915_module_load@load.html
> > 
> >   * igt@i915_pm_backlight@basic-brightness:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
> >    [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
> >    [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html
> > 
> >   * igt@i915_pm_rps@basic-api:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
> >    [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
> >    [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
> >    [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_rps@basic-api.html
> > 
> >   * igt@i915_selftest@live@gt_heartbeat:
> >     - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
> >    [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> >    [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> > 
> >   * igt@i915_selftest@live@gt_mocs:
> >     - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
> >    [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> >    [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> > 
> >   * igt@i915_selftest@live@gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
> >    [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html
> > 
> >   * igt@kms_addfb_basic@basic-x-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
> >    [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@basic-y-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
> >    [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
> >    [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@tile-pitch-mismatch:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
> >    [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html
> > 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
> >    [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
> >    [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
> >    [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
> >    [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
> >    [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
> >    [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
> >    [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> >     - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
> >    [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
> >    [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
> >    [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> >     - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
> >    [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
> >    [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
> >    [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
> >    [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
> >    [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
> >    [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
> >    [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
> >    [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
> >    [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
> >    [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
> >    [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> > 
> >   * igt@kms_force_connector_basic@force-load-detect:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
> >    [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
> >    [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
> >    [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html
> > 
> >   * igt@kms_pipe_crc_basic@suspend-read-crc:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
> >    [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html
> > 
> >   * igt@kms_psr@primary_page_flip:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_psr@primary_page_flip.html
> > 
> >   * igt@kms_psr@sprite_plane_onoff:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html
> > 
> >   * igt@kms_setmode@basic-clone-single-crtc:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
> >    [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
> >    [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
> >    [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html
> > 
> >   * igt@prime_vgem@basic-fence-read:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
> >    [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-fence-read.html
> > 
> >   * igt@prime_vgem@basic-gtt:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-gtt.html
> > 
> >   * igt@prime_vgem@basic-userptr:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
> >    [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
> >    [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
> >    [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-userptr.html
> > 
> >   * igt@prime_vgem@basic-write:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
> >    [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
> >    [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-write.html
> > 
> >   * igt@runner@aborted:
> >     - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
> >    [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@runner@aborted.html
> > 
> >   
> > #### Possible fixes ####
> > 
> >   * igt@gem_exec_suspend@basic-s3@smem:
> >     - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
> >    [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> >    [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> > 
> >   
> >   {name}: This element is suppressed. This means it is ignored when computing
> >           the status of the difference (SUCCESS, WARNING, or FAILURE).
> > 
> >   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
> >   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
> >   [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
> >   [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
> >   [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
> >   [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
> >   [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
> >   [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
> >   [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
> >   [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
> >   [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
> >   [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
> >   [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
> >   [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
> >   [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
> >   [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
> >   [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
> >   [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
> >   [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
> >   [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
> >   [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
> >   [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
> >   [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
> >   [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
> >   [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
> >   [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
> >   [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
> >   [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
> >   [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
> >   [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
> >   [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
> >   [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
> >   [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
> >   [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
> >   [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
> >   [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
> >   [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
> >   [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
> >   [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
> >   [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
> >   [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
> >   [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
> >   [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
> >   [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
> >   [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
> >   [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
> >   [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
> >   [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
> >   [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
> >   [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
> >   [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
> >   [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
> > 
> > 
> > Build changes
> > -------------
> > 
> >   * CI: CI-20190529 -> None
> >   * IGT: IGT_7084 -> IGTPW_8208
> > 
> >   CI-20190529: 20190529
> >   CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
> >   IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> >   IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
> > 
> > == Logs ==
> > 
> > For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (11 preceding siblings ...)
  2022-12-07  0:14 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
@ 2022-12-08  6:29 ` Patchwork
  2022-12-08 15:58 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-08  6:29 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 25628 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
URL   : https://patchwork.freedesktop.org/series/111501/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

Participating hosts (30 -> 44)
------------------------------

  Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
  Missing    (1): fi-cfl-8700k 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8208:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - {bat-jsl-1}:        NOTRUN -> [SKIP][1] +8 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
    - {fi-jsl-1}:         NOTRUN -> [SKIP][2] +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-adl-ddr5:        NOTRUN -> [SKIP][3] +8 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {fi-ehl-2}:         NOTRUN -> [SKIP][4] +8 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
    - {bat-rpls-2}:       NOTRUN -> [SKIP][5] +7 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
    - bat-dg1-6:          NOTRUN -> [SKIP][6] +8 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - {bat-rplp-1}:       NOTRUN -> [SKIP][7] +8 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - {bat-adln-1}:       NOTRUN -> [SKIP][8] +8 similar issues
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - {bat-adlp-9}:       NOTRUN -> [SKIP][9] +8 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-rkl-11600:       NOTRUN -> [SKIP][10] +7 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-adls-5}:       NOTRUN -> [SKIP][11] +7 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - bat-dg1-5:          NOTRUN -> [SKIP][12] +8 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg1-7}:        NOTRUN -> [SKIP][13] +8 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
    - {bat-dg2-9}:        NOTRUN -> [SKIP][14] +8 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - {bat-adlp-6}:       NOTRUN -> [SKIP][15] +7 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-icl-u2:          NOTRUN -> [SKIP][16] +8 similar issues
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-atsm-1}:       NOTRUN -> [SKIP][17] +7 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-jsl-3}:        NOTRUN -> [SKIP][18] +8 similar issues
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-rkl-guc:         NOTRUN -> [SKIP][19] +7 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-11}:       NOTRUN -> [SKIP][20] +8 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - bat-adlp-4:         NOTRUN -> [SKIP][21] +8 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-dg2-8}:        NOTRUN -> [SKIP][22] +8 similar issues
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - {bat-adlm-1}:       NOTRUN -> [SKIP][23] +8 similar issues
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12475 and IGTPW_8208:

### New IGT tests (9) ###

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 1 pass(s) 33 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 1 pass(s) 42 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses : 43 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8208 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@debugfs_test@basic-hwmon:
    - bat-adlp-4:         NOTRUN -> [SKIP][24] ([i915#7456])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@debugfs_test@basic-hwmon.html

  * igt@gem_exec_gttfill@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][25] ([fdo#109271]) +15 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
    - fi-pnv-d510:        [PASS][26] -> [FAIL][27] ([i915#7229])
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@gem_exec_gttfill@basic.html

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][28] ([fdo#109271] / [i915#2190])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@basic:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#4613]) +3 similar issues
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_lmem_swapping@basic.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-bsw-nick:        NOTRUN -> [SKIP][30] ([fdo#109271]) +48 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
    - bat-adlp-4:         NOTRUN -> [SKIP][31] ([i915#4613]) +3 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@gem_mmap@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][32] ([i915#4083])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
    - bat-dg1-6:          NOTRUN -> [SKIP][33] ([i915#4083])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_mmap@basic.html

  * igt@gem_render_tiled_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4079]) +1 similar issue
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_render_tiled_blits@basic.html

  * igt@gem_tiled_blits@basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][35] ([i915#4077]) +2 similar issues
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_blits@basic.html

  * igt@gem_tiled_fence_blits@basic:
    - bat-dg1-6:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@gem_tiled_fence_blits@basic.html

  * igt@gem_tiled_pread_basic:
    - bat-dg1-5:          NOTRUN -> [SKIP][37] ([i915#4079]) +1 similar issue
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
    - bat-adlp-4:         NOTRUN -> [SKIP][38] ([i915#3282])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@gem_tiled_pread_basic.html

  * igt@i915_module_load@load:
    - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][39] ([i915#7430])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@i915_module_load@load.html

  * igt@i915_pm_backlight@basic-brightness:
    - bat-dg1-6:          NOTRUN -> [SKIP][40] ([i915#7561])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
    - bat-dg1-5:          NOTRUN -> [SKIP][41] ([i915#7561])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_backlight@basic-brightness.html

  * igt@i915_pm_rps@basic-api:
    - bat-dg1-6:          NOTRUN -> [SKIP][42] ([i915#6621])
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
    - bat-adlp-4:         NOTRUN -> [SKIP][43] ([i915#6621])
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
    - bat-dg1-5:          NOTRUN -> [SKIP][44] ([i915#6621])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i915_pm_rps@basic-api.html

  * igt@i915_selftest@live@gt_heartbeat:
    - fi-glk-j4005:       [PASS][45] -> [DMESG-FAIL][46] ([i915#5334])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html

  * igt@i915_selftest@live@gt_mocs:
    - fi-rkl-guc:         [PASS][47] -> [INCOMPLETE][48] ([i915#4983])
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html

  * igt@i915_selftest@live@gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][49] ([i915#1886])
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html

  * igt@i915_selftest@live@late_gt_pm:
    - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][50] ([i915#6483])
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@i915_selftest@live@late_gt_pm.html

  * igt@kms_addfb_basic@basic-x-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-x-tiled-legacy.html

  * igt@kms_addfb_basic@basic-y-tiled-legacy:
    - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
    - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@basic-y-tiled-legacy.html

  * igt@kms_addfb_basic@tile-pitch-mismatch:
    - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_addfb_basic@tile-pitch-mismatch.html

  * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
    - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@kms_chamelium_edid@dp-edid-read.html

  * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
    - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@kms_chamelium_edid@hdmi-edid-read.html

  * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
    - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@kms_chamelium_frames@dp-crc-fast.html

  * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
    - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt@kms_chamelium_frames@hdmi-crc-fast.html

  * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
    - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
    - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/igt@kms_chamelium_hpd@dp-hpd-fast.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
    - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
    - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@kms_chamelium_hpd@hdmi-hpd-fast.html

  * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
    - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt@kms_chamelium_hpd@vga-hpd-fast.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
    - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
    - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
    - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html

  * igt@kms_force_connector_basic@force-load-detect:
    - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
    - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
    - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pipe_crc_basic@suspend-read-crc:
    - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_pipe_crc_basic@suspend-read-crc.html

  * igt@kms_psr@primary_page_flip:
    - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_psr@primary_page_flip.html

  * igt@kms_psr@sprite_plane_onoff:
    - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_psr@sprite_plane_onoff.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
    - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
    - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@prime_vgem@basic-fence-read:
    - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-fence-read.html

  * igt@prime_vgem@basic-gtt:
    - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
    - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-gtt.html

  * igt@prime_vgem@basic-userptr:
    - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
    - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
    - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@prime_vgem@basic-userptr.html

  * igt@prime_vgem@basic-write:
    - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
    - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-write.html

  * igt@runner@aborted:
    - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt@runner@aborted.html

  
#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
  [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
  [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
  [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
  [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
  [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
  [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
  [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
  [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
  [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
  [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
  [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
  [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
  [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
  [i915#6483]: https://gitlab.freedesktop.org/drm/intel/issues/6483
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
  [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
  [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
  [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
  [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
  [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
  [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7084 -> IGTPW_8208

  CI-20190529: 20190529
  CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
  IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

[-- Attachment #2: Type: text/html, Size: 30446 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-12-08  4:55       ` Yedireswarapu, SaiX Nandan
@ 2022-12-08  6:37         ` Yedireswarapu, SaiX Nandan
  0 siblings, 0 replies; 25+ messages in thread
From: Yedireswarapu, SaiX Nandan @ 2022-12-08  6:37 UTC (permalink / raw)
  To: Latvala, Petri, Kamil Konieczny, igt-dev

Hi,

Issue re-reported,
https://patchwork.freedesktop.org/series/111501/


Thanks,
Y Sai Nandan

-----Original Message-----
From: Yedireswarapu, SaiX Nandan 
Sent: Thursday, December 8, 2022 10:25 AM
To: Latvala, Petri <petri.latvala@intel.com>; Kamil Konieczny <kamil.konieczny@linux.intel.com>; igt-dev@lists.freedesktop.org
Subject: RE: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)

Hi,

Will address possible regressions and update here shortly.

Thanks,
Y Sai Nandan

-----Original Message-----
From: Latvala, Petri <petri.latvala@intel.com>
Sent: Wednesday, December 7, 2022 8:25 PM
To: Kamil Konieczny <kamil.konieczny@linux.intel.com>; igt-dev@lists.freedesktop.org; Yedireswarapu, SaiX Nandan <saix.nandan.yedireswarapu@intel.com>
Subject: Re: [igt-dev] ✗ Fi.CI.BAT: failure for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)

On Wed, Dec 07, 2022 at 01:59:03PM +0100, Kamil Konieczny wrote:
> Hi Sai,
> 
> On 2022-12-07 at 00:14:37 -0000, Patchwork wrote:
> > == Series Details ==
> > 
> > Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
> > URL   : https://patchwork.freedesktop.org/series/111501/
> > State : failure
> > 
> > == Summary ==
> > 
> > CI Bug Log - changes from CI_DRM_12475 -> IGTPW_8208 
> > ====================================================
> > 
> > Summary
> > -------
> > 
> >   **FAILURE**
> > 
> >   Serious unknown changes coming with IGTPW_8208 absolutely need to be
> >   verified manually.
> >   
> >   If you think the reported changes have nothing to do with the changes
> >   introduced in IGTPW_8208, please notify your bug team to allow them
> >   to document this new failure mode, which will reduce false positives in CI.
> > 
> >   External URL: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> > 
> > Participating hosts (30 -> 44)
> > ------------------------------
> > 
> >   Additional (15): fi-kbl-soraka bat-kbl-2 bat-adls-5 bat-dg1-6 bat-dg1-5 fi-bsw-n3050 bat-dg2-8 bat-adlp-9 bat-dg2-9 bat-adlp-6 bat-adlp-4 bat-atsm-1 bat-jsl-3 bat-dg2-11 fi-bsw-nick 
> >   Missing    (1): fi-cfl-8700k 
> > 
> > Possible new issues
> > -------------------
> > 
> >   Here are the unknown changes that may have been introduced in IGTPW_8208:
> > 
> > ### IGT changes ###
> > 
> > #### Possible regressions ####
> > 
> >   * igt@i915_selftest@live@late_gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [INCOMPLETE][1]
> >    [1]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/ig
> > t@i915_selftest@live@late_gt_pm.html
> > 
> 
> This i915_selftest is unrelated to changes in chamelium.
> 
> Below kms_chamelium_* tests should skip on all i915 HW.

For new tests filters can be added/modified when the results appear in postmerge.

We have some chamelium hosts in BAT so it's not all i915 HW. But the existing chamelium-skip filter is the one where these new test names can be added.


--
Petri Latvala



> 
> Regards,
> Kamil
> 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - {bat-jsl-1}:        NOTRUN -> [SKIP][2] +8 similar issues
> >    [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-1/igt@kms_chamelium_edid@dp-edid-read.html
> >     - {fi-jsl-1}:         NOTRUN -> [SKIP][3] +8 similar issues
> >    [3]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-jsl-1/igt@kms
> > _chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-adl-ddr5:        NOTRUN -> [SKIP][4] +8 similar issues
> >    [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-adl-ddr5/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {fi-ehl-2}:         NOTRUN -> [SKIP][5] +8 similar issues
> >    [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ehl-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - {bat-rpls-2}:       NOTRUN -> [SKIP][6] +7 similar issues
> >    [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rpls-2/igt@kms_chamelium_edid@hdmi-edid-read.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][7] +8 similar issues
> >    [7]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - {bat-rplp-1}:       NOTRUN -> [SKIP][8] +8 similar issues
> >    [8]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@k
> > ms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - {bat-adln-1}:       NOTRUN -> [SKIP][9] +8 similar issues
> >    [9]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adln-1/igt@k
> > ms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - {bat-adlp-9}:       NOTRUN -> [SKIP][10] +8 similar issues
> >    [10]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-9/igt@k
> > ms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-rkl-11600:       NOTRUN -> [SKIP][11] +7 similar issues
> >    [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-11600/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-adls-5}:       NOTRUN -> [SKIP][12] +7 similar issues
> >    [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adls-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][13] +8 similar issues
> >    [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg1-7}:        NOTRUN -> [SKIP][14] +8 similar issues
> >    [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-7/igt@kms_chamelium_hpd@dp-hpd-fast.html
> >     - {bat-dg2-9}:        NOTRUN -> [SKIP][15] +8 similar issues
> >    [15]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-9/igt@km
> > s_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - {bat-adlp-6}:       NOTRUN -> [SKIP][16] +7 similar issues
> >    [16]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-6/igt@k
> > ms_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-icl-u2:          NOTRUN -> [SKIP][17] +8 similar issues
> >    [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-icl-u2/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-atsm-1}:       NOTRUN -> [SKIP][18] +7 similar issues
> >    [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-atsm-1/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-jsl-3}:        NOTRUN -> [SKIP][19] +8 similar issues
> >    [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-jsl-3/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-rkl-guc:         NOTRUN -> [SKIP][20] +7 similar issues
> >    [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-11}:       NOTRUN -> [SKIP][21] +8 similar issues
> >    [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-11/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][22] +8 similar issues
> >    [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-dg2-8}:        NOTRUN -> [SKIP][23] +8 similar issues
> >    [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg2-8/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - {bat-adlm-1}:       NOTRUN -> [SKIP][24] +8 similar issues
> >    [24]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlm-1/igt@k
> > ms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   
> > New tests
> > ---------
> > 
> >   New tests have been introduced between CI_DRM_12475 and IGTPW_8208:
> > 
> > ### New IGT tests (9) ###
> > 
> >   * igt@kms_chamelium_edid@dp-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@hdmi-edid-read:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_edid@vga-edid-read:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@dp-crc-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_frames@hdmi-crc-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@common-hpd-after-suspend:
> >     - Statuses : 1 pass(s) 33 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@dp-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@hdmi-hpd-fast:
> >     - Statuses : 1 pass(s) 42 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   * igt@kms_chamelium_hpd@vga-hpd-fast:
> >     - Statuses : 43 skip(s)
> >     - Exec time: [0.0] s
> > 
> >   
> > 
> > Known issues
> > ------------
> > 
> >   Here are the changes found in IGTPW_8208 that come from known issues:
> > 
> > ### IGT changes ###
> > 
> > #### Issues hit ####
> > 
> >   * igt@debugfs_test@basic-hwmon:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][25] ([i915#7456])
> >    [25]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@d
> > ebugfs_test@basic-hwmon.html
> > 
> >   * igt@gem_exec_gttfill@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][26] ([fdo#109271]) +15 similar issues
> >    [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/igt@gem_exec_gttfill@basic.html
> >     - fi-pnv-d510:        [PASS][27] -> [FAIL][28] ([i915#7229])
> >    [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-pnv-d510/igt@gem_exec_gttfill@basic.html
> >    [28]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@
> > gem_exec_gttfill@basic.html
> > 
> >   * igt@gem_huc_copy@huc-copy:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][29] ([fdo#109271] / [i915#2190])
> >    [29]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/ig
> > t@gem_huc_copy@huc-copy.html
> > 
> >   * igt@gem_lmem_swapping@basic:
> >     - fi-kbl-soraka:      NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#4613]) +3 similar issues
> >    [30]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/ig
> > t@gem_lmem_swapping@basic.html
> > 
> >   * igt@gem_lmem_swapping@parallel-random-engines:
> >     - fi-bsw-nick:        NOTRUN -> [SKIP][31] ([fdo#109271]) +48 similar issues
> >    [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-nick/igt@gem_lmem_swapping@parallel-random-engines.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][32] ([i915#4613]) +3 similar issues
> >    [32]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@g
> > em_lmem_swapping@parallel-random-engines.html
> > 
> >   * igt@gem_mmap@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][33] ([i915#4083])
> >    [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_mmap@basic.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][34] ([i915#4083])
> >    [34]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@ge
> > m_mmap@basic.html
> > 
> >   * igt@gem_render_tiled_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][35] ([i915#4079]) +1 similar issue
> >    [35]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@ge
> > m_render_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_blits@basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][36] ([i915#4077]) +2 similar issues
> >    [36]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@ge
> > m_tiled_blits@basic.html
> > 
> >   * igt@gem_tiled_fence_blits@basic:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][37] ([i915#4077]) +2 similar issues
> >    [37]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@ge
> > m_tiled_fence_blits@basic.html
> > 
> >   * igt@gem_tiled_pread_basic:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][38] ([i915#4079]) +1 similar issue
> >    [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@gem_tiled_pread_basic.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][39] ([i915#3282])
> >    [39]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@g
> > em_tiled_pread_basic.html
> > 
> >   * igt@i915_module_load@load:
> >     - fi-bsw-n3050:       NOTRUN -> [DMESG-WARN][40] ([i915#7430])
> >    [40]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt
> > @i915_module_load@load.html
> > 
> >   * igt@i915_pm_backlight@basic-brightness:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][41] ([i915#7561])
> >    [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_backlight@basic-brightness.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][42] ([i915#7561])
> >    [42]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i9
> > 15_pm_backlight@basic-brightness.html
> > 
> >   * igt@i915_pm_rps@basic-api:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][43] ([i915#6621])
> >    [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@i915_pm_rps@basic-api.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][44] ([i915#6621])
> >    [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@i915_pm_rps@basic-api.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][45] ([i915#6621])
> >    [45]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@i9
> > 15_pm_rps@basic-api.html
> > 
> >   * igt@i915_selftest@live@gt_heartbeat:
> >     - fi-glk-j4005:       [PASS][46] -> [DMESG-FAIL][47] ([i915#5334])
> >    [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-glk-j4005/igt@i915_selftest@live@gt_heartbeat.html
> >    [47]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt
> > @i915_selftest@live@gt_heartbeat.html
> > 
> >   * igt@i915_selftest@live@gt_mocs:
> >     - fi-rkl-guc:         [PASS][48] -> [INCOMPLETE][49] ([i915#4983])
> >    [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/fi-rkl-guc/igt@i915_selftest@live@gt_mocs.html
> >    [49]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-rkl-guc/igt@i
> > 915_selftest@live@gt_mocs.html
> > 
> >   * igt@i915_selftest@live@gt_pm:
> >     - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][50] ([i915#1886])
> >    [50]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-soraka/ig
> > t@i915_selftest@live@gt_pm.html
> > 
> >   * igt@kms_addfb_basic@basic-x-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][51] ([i915#4212]) +7 similar issues
> >    [51]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@km
> > s_addfb_basic@basic-x-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@basic-y-tiled-legacy:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][52] ([i915#4215])
> >    [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_addfb_basic@basic-y-tiled-legacy.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][53] ([i915#4215])
> >    [53]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_addfb_basic@basic-y-tiled-legacy.html
> > 
> >   * igt@kms_addfb_basic@tile-pitch-mismatch:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][54] ([i915#4212]) +7 similar issues
> >    [54]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_addfb_basic@tile-pitch-mismatch.html
> > 
> >   * {igt@kms_chamelium_edid@dp-edid-read} (NEW):
> >     - fi-pnv-d510:        NOTRUN -> [SKIP][55] ([fdo#109271]) +8 similar issues
> >    [55]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-pnv-d510/igt@
> > kms_chamelium_edid@dp-edid-read.html
> > 
> >   * {igt@kms_chamelium_edid@hdmi-edid-read} (NEW):
> >     - fi-cfl-guc:         NOTRUN -> [SKIP][56] ([fdo#109271]) +8 similar issues
> >    [56]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-guc/igt@k
> > ms_chamelium_edid@hdmi-edid-read.html
> > 
> >   * {igt@kms_chamelium_frames@dp-crc-fast} (NEW):
> >     - fi-ilk-650:         NOTRUN -> [SKIP][57] ([fdo#109271]) +8 similar issues
> >    [57]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ilk-650/igt@k
> > ms_chamelium_frames@dp-crc-fast.html
> > 
> >   * {igt@kms_chamelium_frames@hdmi-crc-fast} (NEW):
> >     - fi-cfl-8109u:       NOTRUN -> [SKIP][58] ([fdo#109271]) +8 similar issues
> >    [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-cfl-8109u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-7567u:       NOTRUN -> [SKIP][59] ([fdo#109271]) +8 similar issues
> >    [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-7567u/igt@kms_chamelium_frames@hdmi-crc-fast.html
> >     - fi-kbl-8809g:       NOTRUN -> [SKIP][60] ([fdo#109271]) +7 similar issues
> >    [60]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-kbl-8809g/igt
> > @kms_chamelium_frames@hdmi-crc-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@common-hpd-after-suspend} (NEW):
> >     - fi-glk-j4005:       NOTRUN -> [SKIP][61] ([fdo#109271]) +8 similar issues
> >    [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-glk-j4005/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
> >     - fi-snb-2600:        NOTRUN -> [SKIP][62] ([fdo#109271]) +8 similar issues
> >    [62]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-snb-2600/igt@
> > kms_chamelium_hpd@common-hpd-after-suspend.html
> > 
> >   * {igt@kms_chamelium_hpd@dp-hpd-fast} (NEW):
> >     - fi-skl-6700k2:      NOTRUN -> [SKIP][63] ([fdo#109271]) +4 similar issues
> >    [63]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-6700k2/ig
> > t@kms_chamelium_hpd@dp-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@hdmi-hpd-fast} (NEW):
> >     - fi-blb-e6850:       NOTRUN -> [SKIP][64] ([fdo#109271]) +8 similar issues
> >    [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-blb-e6850/igt@kms_chamelium_hpd@hdmi-hpd-fast.html
> >     - {bat-kbl-2}:        NOTRUN -> [SKIP][65] ([fdo#109271]) +8 similar issues
> >    [65]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-kbl-2/igt@km
> > s_chamelium_hpd@hdmi-hpd-fast.html
> > 
> >   * {igt@kms_chamelium_hpd@vga-hpd-fast} (NEW):
> >     - fi-apl-guc:         NOTRUN -> [SKIP][66] ([fdo#109271]) +8 similar issues
> >    [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-apl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][67] ([fdo#109271]) +7 similar issues
> >    [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bdw-gvtdvm/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-bsw-kefka:       NOTRUN -> [SKIP][68] ([fdo#109271]) +8 similar issues
> >    [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-kefka/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-skl-guc:         NOTRUN -> [SKIP][69] ([fdo#109271]) +8 similar issues
> >    [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-skl-guc/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-hsw-4770:        NOTRUN -> [SKIP][70] ([fdo#109271]) +8 similar issues
> >    [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-hsw-4770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-ivb-3770:        NOTRUN -> [SKIP][71] ([fdo#109271]) +8 similar issues
> >    [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-ivb-3770/igt@kms_chamelium_hpd@vga-hpd-fast.html
> >     - fi-elk-e7500:       NOTRUN -> [SKIP][72] ([fdo#109271]) +8 similar issues
> >    [72]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-elk-e7500/igt
> > @kms_chamelium_hpd@vga-hpd-fast.html
> > 
> >   * igt@kms_cursor_legacy@basic-busy-flip-before-cursor:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][73] ([i915#4103])
> >    [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][74] ([i915#4103] / [i915#4213])
> >    [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_cursor_legacy@basic-busy-flip-before-cursor.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][75] ([i915#4103] / [i915#4213])
> >    [75]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_cursor_legacy@basic-busy-flip-before-cursor.html
> > 
> >   * igt@kms_force_connector_basic@force-load-detect:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][76] ([i915#4093]) +3 similar issues
> >    [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][77] ([fdo#109285])
> >    [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_force_connector_basic@force-load-detect.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][78] ([fdo#109285])
> >    [78]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_force_connector_basic@force-load-detect.html
> > 
> >   * igt@kms_pipe_crc_basic@suspend-read-crc:
> >     - bat-adlp-4:         NOTRUN -> [SKIP][79] ([i915#3546])
> >    [79]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@k
> > ms_pipe_crc_basic@suspend-read-crc.html
> > 
> >   * igt@kms_psr@primary_page_flip:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][80] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [80]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@km
> > s_psr@primary_page_flip.html
> > 
> >   * igt@kms_psr@sprite_plane_onoff:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][81] ([i915#1072] / [i915#4078]) +3 similar issues
> >    [81]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@km
> > s_psr@sprite_plane_onoff.html
> > 
> >   * igt@kms_setmode@basic-clone-single-crtc:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][82] ([i915#3555])
> >    [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-dg1-6:          NOTRUN -> [SKIP][83] ([i915#3555])
> >    [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@kms_setmode@basic-clone-single-crtc.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][84] ([i915#3555] / [i915#4579])
> >    [84]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@k
> > ms_setmode@basic-clone-single-crtc.html
> > 
> >   * igt@prime_vgem@basic-fence-read:
> >     - bat-dg1-5:          NOTRUN -> [SKIP][85] ([i915#3708]) +3 similar issues
> >    [85]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@pr
> > ime_vgem@basic-fence-read.html
> > 
> >   * igt@prime_vgem@basic-gtt:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][86] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-gtt.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][87] ([i915#3708] / [i915#4077]) +1 similar issue
> >    [87]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@pr
> > ime_vgem@basic-gtt.html
> > 
> >   * igt@prime_vgem@basic-userptr:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][88] ([i915#3708] / [i915#4873])
> >    [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-userptr.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][89] ([fdo#109295] / [i915#3301] / [i915#3708])
> >    [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@prime_vgem@basic-userptr.html
> >     - bat-dg1-5:          NOTRUN -> [SKIP][90] ([i915#3708] / [i915#4873])
> >    [90]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-5/igt@pr
> > ime_vgem@basic-userptr.html
> > 
> >   * igt@prime_vgem@basic-write:
> >     - bat-dg1-6:          NOTRUN -> [SKIP][91] ([i915#3708]) +3 similar issues
> >    [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-dg1-6/igt@prime_vgem@basic-write.html
> >     - bat-adlp-4:         NOTRUN -> [SKIP][92] ([fdo#109295] / [i915#3291] / [i915#3708]) +2 similar issues
> >    [92]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-adlp-4/igt@p
> > rime_vgem@basic-write.html
> > 
> >   * igt@runner@aborted:
> >     - fi-bsw-n3050:       NOTRUN -> [FAIL][93] ([i915#4312])
> >    [93]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/fi-bsw-n3050/igt
> > @runner@aborted.html
> > 
> >   
> > #### Possible fixes ####
> > 
> >   * igt@gem_exec_suspend@basic-s3@smem:
> >     - {bat-rplp-1}:       [DMESG-WARN][94] ([i915#2867]) -> [PASS][95]
> >    [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/bat-rplp-1/igt@gem_exec_suspend@basic-s3@smem.html
> >    [95]: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/bat-rplp-1/igt@g
> > em_exec_suspend@basic-s3@smem.html
> > 
> >   
> >   {name}: This element is suppressed. This means it is ignored when computing
> >           the status of the difference (SUCCESS, WARNING, or FAILURE).
> > 
> >   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
> >   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
> >   [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
> >   [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
> >   [i915#1836]: https://gitlab.freedesktop.org/drm/intel/issues/1836
> >   [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
> >   [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
> >   [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
> >   [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
> >   [i915#3003]: https://gitlab.freedesktop.org/drm/intel/issues/3003
> >   [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
> >   [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
> >   [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
> >   [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
> >   [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
> >   [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
> >   [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
> >   [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
> >   [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
> >   [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
> >   [i915#4093]: https://gitlab.freedesktop.org/drm/intel/issues/4093
> >   [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
> >   [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
> >   [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
> >   [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
> >   [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
> >   [i915#4579]: https://gitlab.freedesktop.org/drm/intel/issues/4579
> >   [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
> >   [i915#4873]: https://gitlab.freedesktop.org/drm/intel/issues/4873
> >   [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
> >   [i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
> >   [i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
> >   [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
> >   [i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
> >   [i915#5591]: https://gitlab.freedesktop.org/drm/intel/issues/5591
> >   [i915#6077]: https://gitlab.freedesktop.org/drm/intel/issues/6077
> >   [i915#6078]: https://gitlab.freedesktop.org/drm/intel/issues/6078
> >   [i915#6093]: https://gitlab.freedesktop.org/drm/intel/issues/6093
> >   [i915#6094]: https://gitlab.freedesktop.org/drm/intel/issues/6094
> >   [i915#6166]: https://gitlab.freedesktop.org/drm/intel/issues/6166
> >   [i915#6257]: https://gitlab.freedesktop.org/drm/intel/issues/6257
> >   [i915#6311]: https://gitlab.freedesktop.org/drm/intel/issues/6311
> >   [i915#6434]: https://gitlab.freedesktop.org/drm/intel/issues/6434
> >   [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
> >   [i915#6645]: https://gitlab.freedesktop.org/drm/intel/issues/6645
> >   [i915#7229]: https://gitlab.freedesktop.org/drm/intel/issues/7229
> >   [i915#7357]: https://gitlab.freedesktop.org/drm/intel/issues/7357
> >   [i915#7430]: https://gitlab.freedesktop.org/drm/intel/issues/7430
> >   [i915#7443]: https://gitlab.freedesktop.org/drm/intel/issues/7443
> >   [i915#7456]: https://gitlab.freedesktop.org/drm/intel/issues/7456
> >   [i915#7498]: https://gitlab.freedesktop.org/drm/intel/issues/7498
> >   [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
> > 
> > 
> > Build changes
> > -------------
> > 
> >   * CI: CI-20190529 -> None
> >   * IGT: IGT_7084 -> IGTPW_8208
> > 
> >   CI-20190529: 20190529
> >   CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
> >   IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
> >   IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ 
> > https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
> > 
> > == Logs ==
> > 
> > For more details see: 
> > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
  2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
                   ` (12 preceding siblings ...)
  2022-12-08  6:29 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
@ 2022-12-08 15:58 ` Patchwork
  13 siblings, 0 replies; 25+ messages in thread
From: Patchwork @ 2022-12-08 15:58 UTC (permalink / raw)
  To: Mark Yacoub; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 48649 bytes --]

== Series Details ==

Series: Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4)
URL   : https://patchwork.freedesktop.org/series/111501/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12475_full -> IGTPW_8208_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

Participating hosts (14 -> 8)
------------------------------

  Missing    (6): pig-kbl-iris shard-tglu-9 shard-tglu-10 shard-tglu pig-glk-j5005 pig-skl-6260u 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_8208_full:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium_edid@hdmi-edid-change-during-suspend} (NEW):
    - {shard-rkl}:        NOTRUN -> [SKIP][1] +46 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_chamelium_edid@hdmi-edid-change-during-suspend.html

  * {igt@kms_chamelium_hpd@dp-hpd-storm} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][2] +48 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb8/igt@kms_chamelium_hpd@dp-hpd-storm.html

  * {igt@kms_chamelium_hpd@hdmi-hpd-storm-disable} (NEW):
    - {shard-dg1}:        NOTRUN -> [SKIP][3] +43 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-dg1-17/igt@kms_chamelium_hpd@hdmi-hpd-storm-disable.html

  * {igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][4] +47 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode.html

  
New tests
---------

  New tests have been introduced between CI_DRM_12475_full and IGTPW_8208_full:

### New IGT tests (63) ###

  * igt@kms_chamelium_audio@dp-audio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@dp-audio-edid:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_audio@hdmi-audio-edid:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-25:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-50:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-0-75:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-blue-to-red:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-green-to-red:
    - Statuses : 3 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-limited-range:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-max:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-negative:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@ctm-red-to-blue:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@degamma:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_color@gamma:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-change-during-suspend:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-read:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-resolution-list:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-non-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@dp-mode-timings:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-change-during-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-read:
    - Statuses : 3 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-4k:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-edid-stress-resolution-non-4k:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@hdmi-mode-timings:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_edid@vga-edid-read:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-crc-single:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@dp-frame-dump:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-aspect-ratio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-cmp-planar-formats:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-fast:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_frames@hdmi-crc-multiple:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-nonplanar-formats:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-crc-single:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@hdmi-frame-dump:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_frames@vga-frame-dump:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-after-suspend:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-enable-disable-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-fast:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-for-each-pipe:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-storm-disable:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@dp-hpd-with-enabled-mode:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_hpd@hdmi-hpd-after-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-enable-disable-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-fast:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-for-each-pipe:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-storm-disable:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@hdmi-hpd-with-enabled-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-after-suspend:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-enable-disable-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-fast:
    - Statuses :
    - Exec time: [None] s

  * igt@kms_chamelium_hpd@vga-hpd-for-each-pipe:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-with-enabled-mode:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@kms_chamelium_hpd@vga-hpd-without-ddc:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_8208_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ccs@block-copy-inplace:
    - shard-tglb:         NOTRUN -> [SKIP][5] ([i915#3555] / [i915#5325])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@gem_ccs@block-copy-inplace.html
    - shard-iclb:         NOTRUN -> [SKIP][6] ([i915#5327])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb8/igt@gem_ccs@block-copy-inplace.html

  * igt@gem_ctx_exec@basic-nohangcheck:
    - shard-tglb:         [PASS][7] -> [FAIL][8] ([i915#6268])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb3/igt@gem_ctx_exec@basic-nohangcheck.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb7/igt@gem_ctx_exec@basic-nohangcheck.html

  * igt@gem_ctx_persistence@engines-queued:
    - shard-snb:          NOTRUN -> [SKIP][9] ([fdo#109271] / [i915#1099]) +2 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-snb4/igt@gem_ctx_persistence@engines-queued.html

  * igt@gem_exec_balancer@parallel-out-fence:
    - shard-iclb:         [PASS][10] -> [SKIP][11] ([i915#4525])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb2/igt@gem_exec_balancer@parallel-out-fence.html
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@gem_exec_balancer@parallel-out-fence.html

  * igt@gem_exec_fair@basic-none-solo@rcs0:
    - shard-tglb:         [PASS][12] -> [FAIL][13] ([i915#2842])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb6/igt@gem_exec_fair@basic-none-solo@rcs0.html
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@gem_exec_fair@basic-none-solo@rcs0.html

  * igt@gem_exec_fair@basic-none@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][14] ([i915#2842])
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@gem_exec_fair@basic-none@vcs1.html

  * igt@gem_exec_params@no-vebox:
    - shard-tglb:         NOTRUN -> [SKIP][15] ([fdo#109283] / [i915#4877])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb7/igt@gem_exec_params@no-vebox.html

  * igt@gem_huc_copy@huc-copy:
    - shard-tglb:         [PASS][16] -> [SKIP][17] ([i915#2190])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb1/igt@gem_huc_copy@huc-copy.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@parallel-random-verify-ccs:
    - shard-apl:          NOTRUN -> [SKIP][18] ([fdo#109271] / [i915#4613])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl6/igt@gem_lmem_swapping@parallel-random-verify-ccs.html
    - shard-tglb:         NOTRUN -> [SKIP][19] ([i915#4613]) +1 similar issue
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@gem_lmem_swapping@parallel-random-verify-ccs.html
    - shard-iclb:         NOTRUN -> [SKIP][20] ([i915#4613])
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb8/igt@gem_lmem_swapping@parallel-random-verify-ccs.html

  * igt@gem_pread@exhaustion:
    - shard-tglb:         NOTRUN -> [WARN][21] ([i915#2658])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@gem_pread@exhaustion.html

  * igt@gem_pxp@dmabuf-shared-protected-dst-is-context-refcounted:
    - shard-iclb:         NOTRUN -> [SKIP][22] ([i915#4270])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@gem_pxp@dmabuf-shared-protected-dst-is-context-refcounted.html
    - shard-tglb:         NOTRUN -> [SKIP][23] ([i915#4270])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb3/igt@gem_pxp@dmabuf-shared-protected-dst-is-context-refcounted.html

  * igt@gem_softpin@evict-single-offset:
    - shard-tglb:         [PASS][24] -> [FAIL][25] ([i915#4171])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb5/igt@gem_softpin@evict-single-offset.html
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@gem_softpin@evict-single-offset.html

  * igt@gem_userptr_blits@input-checking:
    - shard-snb:          NOTRUN -> [DMESG-WARN][26] ([i915#4991])
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-snb4/igt@gem_userptr_blits@input-checking.html

  * igt@gen3_mixed_blits:
    - shard-iclb:         NOTRUN -> [SKIP][27] ([fdo#109289]) +1 similar issue
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@gen3_mixed_blits.html
    - shard-tglb:         NOTRUN -> [SKIP][28] ([fdo#109289])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@gen3_mixed_blits.html

  * igt@gen9_exec_parse@batch-zero-length:
    - shard-tglb:         NOTRUN -> [SKIP][29] ([i915#2527] / [i915#2856])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@gen9_exec_parse@batch-zero-length.html
    - shard-iclb:         NOTRUN -> [SKIP][30] ([i915#2856])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb7/igt@gen9_exec_parse@batch-zero-length.html

  * igt@i915_pm_rc6_residency@rc6-fence:
    - shard-tglb:         [PASS][31] -> [WARN][32] ([i915#2681])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb3/igt@i915_pm_rc6_residency@rc6-fence.html
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb7/igt@i915_pm_rc6_residency@rc6-fence.html

  * igt@i915_pm_rpm@gem-execbuf-stress-pc8:
    - shard-tglb:         NOTRUN -> [SKIP][33] ([fdo#109506] / [i915#2411])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb7/igt@i915_pm_rpm@gem-execbuf-stress-pc8.html

  * igt@i915_pm_rpm@modeset-non-lpsp:
    - shard-tglb:         NOTRUN -> [SKIP][34] ([fdo#111644] / [i915#1397] / [i915#2411])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@i915_pm_rpm@modeset-non-lpsp.html
    - shard-iclb:         NOTRUN -> [SKIP][35] ([fdo#110892])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb3/igt@i915_pm_rpm@modeset-non-lpsp.html

  * igt@kms_big_fb@4-tiled-16bpp-rotate-180:
    - shard-tglb:         NOTRUN -> [SKIP][36] ([i915#5286]) +1 similar issue
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_big_fb@4-tiled-16bpp-rotate-180.html
    - shard-iclb:         NOTRUN -> [SKIP][37] ([i915#5286])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb3/igt@kms_big_fb@4-tiled-16bpp-rotate-180.html

  * igt@kms_big_fb@x-tiled-16bpp-rotate-270:
    - shard-tglb:         NOTRUN -> [SKIP][38] ([fdo#111614])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@kms_big_fb@x-tiled-16bpp-rotate-270.html

  * igt@kms_big_fb@yf-tiled-addfb-size-offset-overflow:
    - shard-tglb:         NOTRUN -> [SKIP][39] ([fdo#111615])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_big_fb@yf-tiled-addfb-size-offset-overflow.html

  * igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip:
    - shard-iclb:         NOTRUN -> [SKIP][40] ([fdo#110723])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip.html

  * igt@kms_big_joiner@invalid-modeset:
    - shard-tglb:         NOTRUN -> [SKIP][41] ([i915#2705])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_big_joiner@invalid-modeset.html

  * igt@kms_ccs@pipe-a-crc-primary-rotation-180-4_tiled_dg2_mc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][42] ([i915#3689] / [i915#6095]) +2 similar issues
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@kms_ccs@pipe-a-crc-primary-rotation-180-4_tiled_dg2_mc_ccs.html

  * igt@kms_ccs@pipe-b-crc-primary-basic-y_tiled_gen12_mc_ccs:
    - shard-iclb:         NOTRUN -> [SKIP][43] ([fdo#109278] / [i915#3886]) +2 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@kms_ccs@pipe-b-crc-primary-basic-y_tiled_gen12_mc_ccs.html
    - shard-tglb:         NOTRUN -> [SKIP][44] ([i915#3689] / [i915#3886])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_ccs@pipe-b-crc-primary-basic-y_tiled_gen12_mc_ccs.html

  * igt@kms_ccs@pipe-b-missing-ccs-buffer-yf_tiled_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][45] ([fdo#111615] / [i915#3689])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@kms_ccs@pipe-b-missing-ccs-buffer-yf_tiled_ccs.html

  * igt@kms_ccs@pipe-c-bad-aux-stride-y_tiled_gen12_rc_ccs_cc:
    - shard-apl:          NOTRUN -> [SKIP][46] ([fdo#109271] / [i915#3886]) +2 similar issues
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl1/igt@kms_ccs@pipe-c-bad-aux-stride-y_tiled_gen12_rc_ccs_cc.html

  * igt@kms_ccs@pipe-c-bad-pixel-format-4_tiled_dg2_rc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][47] ([i915#6095]) +1 similar issue
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@kms_ccs@pipe-c-bad-pixel-format-4_tiled_dg2_rc_ccs.html

  * igt@kms_ccs@pipe-d-bad-rotation-90-4_tiled_dg2_rc_ccs:
    - shard-tglb:         NOTRUN -> [SKIP][48] ([i915#3689]) +1 similar issue
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@kms_ccs@pipe-d-bad-rotation-90-4_tiled_dg2_rc_ccs.html

  * igt@kms_ccs@pipe-d-random-ccs-data-4_tiled_dg2_rc_ccs_cc:
    - shard-iclb:         NOTRUN -> [SKIP][49] ([fdo#109278]) +2 similar issues
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@kms_ccs@pipe-d-random-ccs-data-4_tiled_dg2_rc_ccs_cc.html

  * {igt@kms_chamelium_color@ctm-0-75} (NEW):
    - shard-apl:          NOTRUN -> [SKIP][50] ([fdo#109271]) +94 similar issues
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl3/igt@kms_chamelium_color@ctm-0-75.html

  * {igt@kms_chamelium_color@ctm-green-to-red} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][51] ([fdo#109284]) +10 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@kms_chamelium_color@ctm-green-to-red.html

  * {igt@kms_chamelium_color@gamma} (NEW):
    - shard-tglb:         NOTRUN -> [SKIP][52] ([fdo#109284]) +9 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@kms_chamelium_color@gamma.html

  * igt@kms_content_protection@content_type_change:
    - shard-tglb:         NOTRUN -> [SKIP][53] ([i915#7118])
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb3/igt@kms_content_protection@content_type_change.html
    - shard-iclb:         NOTRUN -> [SKIP][54] ([i915#7118])
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@kms_content_protection@content_type_change.html

  * igt@kms_cursor_crc@cursor-onscreen-max-size:
    - shard-tglb:         NOTRUN -> [SKIP][55] ([i915#3555])
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_cursor_crc@cursor-onscreen-max-size.html

  * igt@kms_cursor_legacy@2x-cursor-vs-flip-atomic:
    - shard-iclb:         NOTRUN -> [SKIP][56] ([fdo#109274]) +2 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb6/igt@kms_cursor_legacy@2x-cursor-vs-flip-atomic.html

  * igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy:
    - shard-tglb:         NOTRUN -> [SKIP][57] ([fdo#109274] / [fdo#111825]) +2 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy.html

  * igt@kms_cursor_legacy@cursor-vs-flip@toggle:
    - shard-iclb:         [PASS][58] -> [FAIL][59] ([i915#5072])
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb3/igt@kms_cursor_legacy@cursor-vs-flip@toggle.html
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb7/igt@kms_cursor_legacy@cursor-vs-flip@toggle.html

  * igt@kms_flip@2x-flip-vs-modeset:
    - shard-tglb:         NOTRUN -> [SKIP][60] ([fdo#109274] / [fdo#111825] / [i915#3637]) +2 similar issues
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_flip@2x-flip-vs-modeset.html

  * igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-downscaling@pipe-a-valid-mode:
    - shard-iclb:         NOTRUN -> [SKIP][61] ([i915#2587] / [i915#2672]) +2 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb6/igt@kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-downscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling@pipe-a-default-mode:
    - shard-iclb:         [PASS][62] -> [SKIP][63] ([i915#3555]) +1 similar issue
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb3/igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling@pipe-a-default-mode.html
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling@pipe-a-default-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][64] ([i915#2672]) +6 similar issues
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb3/igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling@pipe-a-default-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling@pipe-a-valid-mode:
    - shard-tglb:         NOTRUN -> [SKIP][65] ([i915#2587] / [i915#2672]) +1 similar issue
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb6/igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling@pipe-a-valid-mode.html

  * igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling@pipe-a-default-mode:
    - shard-iclb:         NOTRUN -> [SKIP][66] ([i915#3555])
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling@pipe-a-default-mode.html

  * igt@kms_force_connector_basic@force-load-detect:
    - shard-tglb:         NOTRUN -> [SKIP][67] ([fdo#109285])
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@kms_force_connector_basic@force-load-detect.html
    - shard-iclb:         NOTRUN -> [SKIP][68] ([fdo#109285])
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-gtt:
    - shard-iclb:         NOTRUN -> [SKIP][69] ([fdo#109280]) +6 similar issues
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-mmap-wc:
    - shard-tglb:         NOTRUN -> [SKIP][70] ([i915#6497]) +5 similar issues
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-pwrite:
    - shard-tglb:         NOTRUN -> [SKIP][71] ([fdo#109280] / [fdo#111825]) +10 similar issues
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-pwrite.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-a-edp-1:
    - shard-iclb:         [PASS][72] -> [SKIP][73] ([i915#5235]) +2 similar issues
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb1/igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-a-edp-1.html
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-a-edp-1.html

  * igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-25@pipe-c-edp-1:
    - shard-tglb:         NOTRUN -> [SKIP][74] ([i915#5235]) +3 similar issues
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb3/igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-25@pipe-c-edp-1.html

  * igt@kms_psr2_su@page_flip-nv12:
    - shard-iclb:         NOTRUN -> [SKIP][75] ([fdo#109642] / [fdo#111068] / [i915#658])
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb3/igt@kms_psr2_su@page_flip-nv12.html

  * igt@kms_psr@psr2_cursor_mmap_gtt:
    - shard-tglb:         NOTRUN -> [FAIL][76] ([i915#132] / [i915#3467]) +2 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb7/igt@kms_psr@psr2_cursor_mmap_gtt.html

  * igt@kms_psr@psr2_primary_mmap_cpu:
    - shard-iclb:         NOTRUN -> [SKIP][77] ([fdo#109441]) +1 similar issue
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@kms_psr@psr2_primary_mmap_cpu.html

  * igt@kms_psr@psr2_primary_page_flip:
    - shard-iclb:         [PASS][78] -> [SKIP][79] ([fdo#109441]) +2 similar issues
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb2/igt@kms_psr@psr2_primary_page_flip.html
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb3/igt@kms_psr@psr2_primary_page_flip.html

  * igt@kms_psr_stress_test@flip-primary-invalidate-overlay:
    - shard-tglb:         [PASS][80] -> [SKIP][81] ([i915#5519])
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb1/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html
    - shard-iclb:         [PASS][82] -> [SKIP][83] ([i915#5519])
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb1/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb5/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html

  * igt@kms_rotation_crc@bad-pixel-format:
    - shard-snb:          NOTRUN -> [SKIP][84] ([fdo#109271]) +171 similar issues
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-snb7/igt@kms_rotation_crc@bad-pixel-format.html

  * igt@kms_tv_load_detect@load-detect:
    - shard-tglb:         NOTRUN -> [SKIP][85] ([fdo#109309])
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@kms_tv_load_detect@load-detect.html

  * igt@prime_vgem@fence-write-hang:
    - shard-iclb:         NOTRUN -> [SKIP][86] ([fdo#109295])
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@prime_vgem@fence-write-hang.html
    - shard-tglb:         NOTRUN -> [SKIP][87] ([fdo#109295])
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb5/igt@prime_vgem@fence-write-hang.html

  * igt@sysfs_clients@fair-0:
    - shard-tglb:         NOTRUN -> [SKIP][88] ([i915#2994]) +1 similar issue
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb2/igt@sysfs_clients@fair-0.html

  * igt@sysfs_clients@recycle:
    - shard-apl:          NOTRUN -> [SKIP][89] ([fdo#109271] / [i915#2994])
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl6/igt@sysfs_clients@recycle.html
    - shard-iclb:         NOTRUN -> [SKIP][90] ([i915#2994])
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@sysfs_clients@recycle.html

  
#### Possible fixes ####

  * igt@fbdev@unaligned-write:
    - {shard-rkl}:        [SKIP][91] ([i915#2582]) -> [PASS][92] +1 similar issue
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-2/igt@fbdev@unaligned-write.html
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-3/igt@fbdev@unaligned-write.html

  * igt@feature_discovery@psr1:
    - {shard-rkl}:        [SKIP][93] ([i915#658]) -> [PASS][94]
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-1/igt@feature_discovery@psr1.html
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@feature_discovery@psr1.html

  * igt@gem_exec_fair@basic-deadline:
    - {shard-rkl}:        [FAIL][95] ([i915#2846]) -> [PASS][96]
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-6/igt@gem_exec_fair@basic-deadline.html
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-1/igt@gem_exec_fair@basic-deadline.html

  * igt@gem_exec_reloc@basic-write-read-active:
    - {shard-rkl}:        [SKIP][97] ([i915#3281]) -> [PASS][98] +3 similar issues
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-4/igt@gem_exec_reloc@basic-write-read-active.html
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-5/igt@gem_exec_reloc@basic-write-read-active.html

  * igt@gem_ppgtt@blt-vs-render-ctxn:
    - {shard-rkl}:        [FAIL][99] ([i915#4998]) -> [PASS][100]
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-5/igt@gem_ppgtt@blt-vs-render-ctxn.html
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-1/igt@gem_ppgtt@blt-vs-render-ctxn.html

  * igt@gem_pread@snoop:
    - {shard-rkl}:        [SKIP][101] ([i915#3282]) -> [PASS][102] +2 similar issues
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-1/igt@gem_pread@snoop.html
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-5/igt@gem_pread@snoop.html

  * igt@gen9_exec_parse@bb-start-out:
    - {shard-rkl}:        [SKIP][103] ([i915#2527]) -> [PASS][104] +1 similar issue
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-6/igt@gen9_exec_parse@bb-start-out.html
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-5/igt@gen9_exec_parse@bb-start-out.html

  * igt@i915_pm_dc@dc6-dpms:
    - {shard-rkl}:        [SKIP][105] ([i915#3361]) -> [PASS][106]
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-5/igt@i915_pm_dc@dc6-dpms.html
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@i915_pm_dc@dc6-dpms.html

  * igt@i915_pm_rc6_residency@rc6-idle@vcs0:
    - {shard-dg1}:        [FAIL][107] ([i915#3591]) -> [PASS][108] +1 similar issue
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-dg1-18/igt@i915_pm_rc6_residency@rc6-idle@vcs0.html
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-dg1-13/igt@i915_pm_rc6_residency@rc6-idle@vcs0.html

  * igt@i915_pm_rpm@modeset-lpsp:
    - {shard-rkl}:        [SKIP][109] ([i915#1397]) -> [PASS][110]
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-4/igt@i915_pm_rpm@modeset-lpsp.html
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@i915_pm_rpm@modeset-lpsp.html

  * igt@kms_cursor_crc@cursor-suspend@pipe-c-edp-1:
    - shard-tglb:         [DMESG-WARN][111] ([i915#2411] / [i915#2867]) -> [PASS][112]
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-tglb2/igt@kms_cursor_crc@cursor-suspend@pipe-c-edp-1.html
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-tglb1/igt@kms_cursor_crc@cursor-suspend@pipe-c-edp-1.html

  * igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-pwrite:
    - {shard-rkl}:        [SKIP][113] ([i915#1849] / [i915#4098]) -> [PASS][114] +8 similar issues
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-5/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-pwrite.html
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-pwrite.html

  * igt@kms_frontbuffer_tracking@fbc-suspend:
    - shard-apl:          [DMESG-WARN][115] ([i915#180]) -> [PASS][116]
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-apl3/igt@kms_frontbuffer_tracking@fbc-suspend.html
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl2/igt@kms_frontbuffer_tracking@fbc-suspend.html

  * igt@kms_plane@plane-panning-bottom-right@pipe-a-planes:
    - {shard-rkl}:        [SKIP][117] ([i915#1849] / [i915#3558]) -> [PASS][118] +1 similar issue
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-5/igt@kms_plane@plane-panning-bottom-right@pipe-a-planes.html
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_plane@plane-panning-bottom-right@pipe-a-planes.html

  * igt@kms_properties@crtc-properties-legacy:
    - {shard-rkl}:        [SKIP][119] ([i915#1849]) -> [PASS][120]
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-2/igt@kms_properties@crtc-properties-legacy.html
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_properties@crtc-properties-legacy.html

  * igt@kms_psr@cursor_plane_move:
    - {shard-rkl}:        [SKIP][121] ([i915#1072]) -> [PASS][122] +1 similar issue
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-2/igt@kms_psr@cursor_plane_move.html
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_psr@cursor_plane_move.html

  * igt@kms_psr@psr2_sprite_mmap_gtt:
    - shard-iclb:         [SKIP][123] ([fdo#109441]) -> [PASS][124] +1 similar issue
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb7/igt@kms_psr@psr2_sprite_mmap_gtt.html
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_psr@psr2_sprite_mmap_gtt.html

  * igt@kms_universal_plane@universal-plane-pipe-b-functional:
    - {shard-rkl}:        [SKIP][125] ([i915#1845] / [i915#4070] / [i915#4098]) -> [PASS][126]
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-2/igt@kms_universal_plane@universal-plane-pipe-b-functional.html
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_universal_plane@universal-plane-pipe-b-functional.html

  * igt@kms_vblank@pipe-b-ts-continuation-idle:
    - {shard-rkl}:        [SKIP][127] ([i915#1845] / [i915#4098]) -> [PASS][128] +17 similar issues
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-1/igt@kms_vblank@pipe-b-ts-continuation-idle.html
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-6/igt@kms_vblank@pipe-b-ts-continuation-idle.html

  * igt@perf@gen12-oa-tlb-invalidate:
    - {shard-rkl}:        [SKIP][129] ([fdo#109289]) -> [PASS][130]
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-5/igt@perf@gen12-oa-tlb-invalidate.html
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-1/igt@perf@gen12-oa-tlb-invalidate.html

  * igt@perf_pmu@module-unload:
    - shard-snb:          [DMESG-WARN][131] ([i915#4528]) -> [PASS][132]
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-snb7/igt@perf_pmu@module-unload.html
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-snb4/igt@perf_pmu@module-unload.html

  * igt@prime_vgem@basic-fence-read:
    - {shard-rkl}:        [SKIP][133] ([fdo#109295] / [i915#3291] / [i915#3708]) -> [PASS][134]
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-rkl-2/igt@prime_vgem@basic-fence-read.html
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-rkl-5/igt@prime_vgem@basic-fence-read.html

  
#### Warnings ####

  * igt@gem_exec_balancer@parallel-ordering:
    - shard-iclb:         [SKIP][135] ([i915#4525]) -> [FAIL][136] ([i915#6117])
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb5/igt@gem_exec_balancer@parallel-ordering.html
   [136]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@gem_exec_balancer@parallel-ordering.html

  * igt@kms_plane_alpha_blend@alpha-basic@pipe-c-dp-1:
    - shard-apl:          [FAIL][137] ([i915#4573]) -> [DMESG-FAIL][138] ([IGT#6]) +1 similar issue
   [137]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-apl7/igt@kms_plane_alpha_blend@alpha-basic@pipe-c-dp-1.html
   [138]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl8/igt@kms_plane_alpha_blend@alpha-basic@pipe-c-dp-1.html

  * igt@kms_psr2_sf@overlay-plane-update-sf-dmg-area:
    - shard-iclb:         [SKIP][139] ([i915#2920]) -> [SKIP][140] ([fdo#111068] / [i915#658])
   [139]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb2/igt@kms_psr2_sf@overlay-plane-update-sf-dmg-area.html
   [140]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb1/igt@kms_psr2_sf@overlay-plane-update-sf-dmg-area.html

  * igt@kms_psr2_sf@plane-move-sf-dmg-area:
    - shard-iclb:         [SKIP][141] ([fdo#111068] / [i915#658]) -> [SKIP][142] ([i915#2920])
   [141]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-iclb8/igt@kms_psr2_sf@plane-move-sf-dmg-area.html
   [142]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-iclb2/igt@kms_psr2_sf@plane-move-sf-dmg-area.html

  * igt@runner@aborted:
    - shard-apl:          ([FAIL][143], [FAIL][144], [FAIL][145]) ([fdo#109271] / [i915#3002] / [i915#4312]) -> ([FAIL][146], [FAIL][147]) ([i915#3002] / [i915#4312])
   [143]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-apl8/igt@runner@aborted.html
   [144]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-apl8/igt@runner@aborted.html
   [145]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12475/shard-apl3/igt@runner@aborted.html
   [146]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl3/igt@runner@aborted.html
   [147]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/shard-apl3/igt@runner@aborted.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [IGT#6]: https://gitlab.freedesktop.org/drm/igt-gpu-tools/issues/6
  [fdo#103375]: https://bugs.freedesktop.org/show_bug.cgi?id=103375
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109283]: https://bugs.freedesktop.org/show_bug.cgi?id=109283
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109291]: https://bugs.freedesktop.org/show_bug.cgi?id=109291
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [fdo#109308]: https://bugs.freedesktop.org/show_bug.cgi?id=109308
  [fdo#109309]: https://bugs.freedesktop.org/show_bug.cgi?id=109309
  [fdo#109312]: https://bugs.freedesktop.org/show_bug.cgi?id=109312
  [fdo#109313]: https://bugs.freedesktop.org/show_bug.cgi?id=109313
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109506]: https://bugs.freedesktop.org/show_bug.cgi?id=109506
  [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
  [fdo#110723]: https://bugs.freedesktop.org/show_bug.cgi?id=110723
  [fdo#110892]: https://bugs.freedesktop.org/show_bug.cgi?id=110892
  [fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068
  [fdo#111614]: https://bugs.freedesktop.org/show_bug.cgi?id=111614
  [fdo#111615]: https://bugs.freedesktop.org/show_bug.cgi?id=111615
  [fdo#111644]: https://bugs.freedesktop.org/show_bug.cgi?id=111644
  [fdo#111656]: https://bugs.freedesktop.org/show_bug.cgi?id=111656
  [fdo#111825]: https://bugs.freedesktop.org/show_bug.cgi?id=111825
  [fdo#112054]: https://bugs.freedesktop.org/show_bug.cgi?id=112054
  [fdo#112283]: https://bugs.freedesktop.org/show_bug.cgi?id=112283
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1099]: https://gitlab.freedesktop.org/drm/intel/issues/1099
  [i915#132]: https://gitlab.freedesktop.org/drm/intel/issues/132
  [i915#1397]: https://gitlab.freedesktop.org/drm/intel/issues/1397
  [i915#1755]: https://gitlab.freedesktop.org/drm/intel/issues/1755
  [i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180
  [i915#1825]: https://gitlab.freedesktop.org/drm/intel/issues/1825
  [i915#1839]: https://gitlab.freedesktop.org/drm/intel/issues/1839
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
  [i915#1850]: https://gitlab.freedesktop.org/drm/intel/issues/1850
  [i915#1937]: https://gitlab.freedesktop.org/drm/intel/issues/1937
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2411]: https://gitlab.freedesktop.org/drm/intel/issues/2411
  [i915#2437]: https://gitlab.freedesktop.org/drm/intel/issues/2437
  [i915#2527]: https://gitlab.freedesktop.org/drm/intel/issues/2527
  [i915#2575]: https://gitlab.freedesktop.org/drm/intel/issues/2575
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2587]: https://gitlab.freedesktop.org/drm/intel/issues/2587
  [i915#2658]: https://gitlab.freedesktop.org/drm/intel/issues/2658
  [i915#2672]: https://gitlab.freedesktop.org/drm/intel/issues/2672
  [i915#2681]: https://gitlab.freedesktop.org/drm/intel/issues/2681
  [i915#2705]: https://gitlab.freedesktop.org/drm/intel/issues/2705
  [i915#280]: https://gitlab.freedesktop.org/drm/intel/issues/280
  [i915#2842]: https://gitlab.freedesktop.org/drm/intel/issues/2842
  [i915#2846]: https://gitlab.freedesktop.org/drm/intel/issues/2846
  [i915#2856]: https://gitlab.freedesktop.org/drm/intel/issues/2856
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#2920]: https://gitlab.freedesktop.org/drm/intel/issues/2920
  [i915#2994]: https://gitlab.freedesktop.org/drm/intel/issues/2994
  [i915#3002]: https://gitlab.freedesktop.org/drm/intel/issues/3002
  [i915#3116]: https://gitlab.freedesktop.org/drm/intel/issues/3116
  [i915#3281]: https://gitlab.freedesktop.org/drm/intel/issues/3281
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3297]: https://gitlab.freedesktop.org/drm/intel/issues/3297
  [i915#3299]: https://gitlab.freedesktop.org/drm/intel/issues/3299
  [i915#3318]: https://gitlab.freedesktop.org/drm/intel/issues/3318
  [i915#3359]: https://gitlab.freedesktop.org/drm/intel/issues/3359
  [i915#3361]: https://gitlab.freedesktop.org/drm/intel/issues/3361
  [i915#3458]: https://gitlab.freedesktop.org/drm/intel/issues/3458
  [i915#3467]: https://gitlab.freedesktop.org/drm/intel/issues/3467
  [i915#3469]: https://gitlab.freedesktop.org/drm/intel/issues/3469
  [i915#3539]: https://gitlab.freedesktop.org/drm/intel/issues/3539
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3558]: https://gitlab.freedesktop.org/drm/intel/issues/3558
  [i915#3591]: https://gitlab.freedesktop.org/drm/intel/issues/3591
  [i915#3637]: https://gitlab.freedesktop.org/drm/intel/issues/3637
  [i915#3638]: https://gitlab.freedesktop.org/drm/intel/issues/3638
  [i915#3689]: https://gitlab.freedesktop.org/drm/intel/issues/3689
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#3734]: https://gitlab.freedesktop.org/drm/intel/issues/3734
  [i915#3826]: https://gitlab.freedesktop.org/drm/intel/issues/3826
  [i915#3886]: https://gitlab.freedesktop.org/drm/intel/issues/3886
  [i915#3936]: https://gitlab.freedesktop.org/drm/intel/issues/3936
  [i915#3955]: https://gitlab.freedesktop.org/drm/intel/issues/3955
  [i915#4070]: https://gitlab.freedesktop.org/drm/intel/issues/4070
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4098]: https://gitlab.freedesktop.org/drm/intel/issues/4098
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4171]: https://gitlab.freedesktop.org/drm/intel/issues/4171
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
  [i915#426]: https://gitlab.freedesktop.org/drm/intel/issues/426
  [i915#4270]: https://gitlab.freedesktop.org/drm/intel/issues/4270
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4349]: https://gitlab.freedesktop.org/drm/intel/issues/4349
  [i915#4525]: https://gitlab.freedesktop.org/drm/intel/issues/4525
  [i915#4528]: https://gitlab.freedesktop.org/drm/intel/issues/4528
  [i915#4538]: https://gitlab.freedesktop.org/drm/intel/issues/4538
  [i915#4565]: https://gitlab.freedesktop.org/drm/intel/issues/4565
  [i915#4573]: https://gitlab.freedesktop.org/drm/intel/issues/4573
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4767]: https://gitlab.freedesktop.org/drm/intel/issues/4767
  [i915#4812]: https://gitlab.freedesktop.org/drm/intel/issues/4812
  [i915#4833]: https://gitlab.freedesktop.org/drm/intel/issues/4833
  [i915#4852]: https://gitlab.freedesktop.org/drm/intel/issues/4852
  [i915#4859]: https://gitlab.freedesktop.org/drm/intel/issues/4859
  [i915#4860]: https://gitlab.freedesktop.org/drm/intel/issues/4860
  [i915#4877]: https://gitlab.freedesktop.org/drm/intel/issues/4877
  [i915#4885]: https://gitlab.freedesktop.org/drm/intel/issues/4885
  [i915#4958]: https://gitlab.freedesktop.org/drm/intel/issues/4958
  [i915#4991]: https://gitlab.freedesktop.org/drm/intel/issues/4991
  [i915#4998]: https://gitlab.freedesktop.org/drm/intel/issues/4998
  [i915#5072]: https://gitlab.freedesktop.org/drm/intel/issues/5072
  [i915#5176]: https://gitlab.freedesktop.org/drm/intel/issues/5176
  [i915#5235]: https://gitlab.freedesktop.org/drm/intel/issues/5235
  [i915#5286]: https://gitlab.freedesktop.org/drm/intel/issues/5286
  [i915#5288]: https://gitlab.freedesktop.org/drm/intel/issues/5288
  [i915#5289]: https://gitlab.freedesktop.org/drm/intel/issues/5289
  [i915#5325]: https://gitlab.freedesktop.org/drm/intel/issues/5325
  [i915#5327]: https://gitlab.freedesktop.org/drm/intel/issues/5327
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#5461]: https://gitlab.freedesktop.org/drm/intel/issues/5461
  [i915#5519]: https://gitlab.freedesktop.org/drm/intel/issues/5519
  [i915#5563]: https://gitlab.freedesktop.org/drm/intel/issues/5563
  [i915#5784]: https://gitlab.freedesktop.org/drm/intel/issues/5784
  [i915#6095]: https://gitlab.freedesktop.org/drm/intel/issues/6095
  [i915#6117]: https://gitlab.freedesktop.org/drm/intel/issues/6117
  [i915#6247]: https://gitlab.freedesktop.org/drm/intel/issues/6247
  [i915#6248]: https://gitlab.freedesktop.org/drm/intel/issues/6248
  [i915#6252]: https://gitlab.freedesktop.org/drm/intel/issues/6252
  [i915#6268]: https://gitlab.freedesktop.org/drm/intel/issues/6268
  [i915#6301]: https://gitlab.freedesktop.org/drm/intel/issues/6301
  [i915#6334]: https://gitlab.freedesktop.org/drm/intel/issues/6334
  [i915#6355]: https://gitlab.freedesktop.org/drm/intel/issues/6355
  [i915#6497]: https://gitlab.freedesktop.org/drm/intel/issues/6497
  [i915#6524]: https://gitlab.freedesktop.org/drm/intel/issues/6524
  [i915#658]: https://gitlab.freedesktop.org/drm/intel/issues/658
  [i915#6768]: https://gitlab.freedesktop.org/drm/intel/issues/6768
  [i915#7116]: https://gitlab.freedesktop.org/drm/intel/issues/7116
  [i915#7118]: https://gitlab.freedesktop.org/drm/intel/issues/7118
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7084 -> IGTPW_8208
  * Piglit: piglit_4509 -> None

  CI-20190529: 20190529
  CI_DRM_12475: ebea1ef56080671403683f4c09e89c3e7b7e28da @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8208: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html
  IGT_7084: ec81855d36887dfe81d5ff513ed6d512773da37e @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8208/index.html

[-- Attachment #2: Type: text/html, Size: 53113 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-12-08 15:58 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-30 20:45 [igt-dev] [PATCH] Chamelium: Split kms_chamelium into multiple kms_chamelium tests Mark Yacoub
2022-11-30 21:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for " Patchwork
2022-12-01 14:44   ` Petri Latvala
2022-11-30 21:38 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
2022-12-01  9:08 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
2022-12-01 14:49 ` [igt-dev] [PATCH] " Petri Latvala
2022-12-01 16:29 ` [igt-dev] [PATCH v2] " Mark Yacoub
2022-12-02  9:48   ` Petri Latvala
2022-12-06 18:56   ` [igt-dev] [PATCH v3] " Mark Yacoub
2022-12-06 23:22     ` [igt-dev] [PATCH v4] " Mark Yacoub
2022-12-07 11:39       ` Kamil Konieczny
2022-12-01 18:13 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev2) Patchwork
2022-12-01 18:44 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
2022-12-02  8:02 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
2022-12-06 19:19 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev3) Patchwork
2022-12-06 19:51 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
2022-12-06 23:45 ` [igt-dev] ✗ GitLab.Pipeline: warning for Chamelium: Split kms_chamelium into multiple kms_chamelium tests (rev4) Patchwork
2022-12-07  0:14 ` [igt-dev] ✗ Fi.CI.BAT: failure " Patchwork
2022-12-07 12:59   ` Kamil Konieczny
2022-12-07 14:55     ` Petri Latvala
2022-12-08  4:55       ` Yedireswarapu, SaiX Nandan
2022-12-08  6:37         ` Yedireswarapu, SaiX Nandan
2022-12-08  4:54     ` Yedireswarapu, SaiX Nandan
2022-12-08  6:29 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
2022-12-08 15:58 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.