xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_chamelium.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2016 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Lyude Paul <[email protected]>
25  */
26 
27 #include "config.h"
28 #include "igt.h"
29 #include "igt_vc4.h"
30 #include "igt_edid.h"
31 #include "igt_eld.h"
32 #include "igt_infoframe.h"
33 
34 #include <fcntl.h>
35 #include <pthread.h>
36 #include <string.h>
37 #include <stdatomic.h>
38 
39 enum test_edid {
40 	TEST_EDID_BASE,
41 	TEST_EDID_ALT,
42 	TEST_EDID_HDMI_AUDIO,
43 	TEST_EDID_DP_AUDIO,
44 	TEST_EDID_ASPECT_RATIO,
45 };
46 #define TEST_EDID_COUNT 5
47 
48 typedef struct {
49 	struct chamelium *chamelium;
50 	struct chamelium_port **ports;
51 	igt_display_t display;
52 	int port_count;
53 
54 	int drm_fd;
55 
56 	struct chamelium_edid *edids[TEST_EDID_COUNT];
57 } data_t;
58 
59 #define HOTPLUG_TIMEOUT 20 /* seconds */
60 #define ONLINE_TIMEOUT 20 /* seconds */
61 
62 #define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
63 #define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
64 
65 #define HPD_TOGGLE_COUNT_VGA 5
66 #define HPD_TOGGLE_COUNT_DP_HDMI 15
67 #define HPD_TOGGLE_COUNT_FAST 3
68 
69 static void
get_connectors_link_status_failed(data_t * data,bool * link_status_failed)70 get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
71 {
72 	drmModeConnector *connector;
73 	uint64_t link_status;
74 	drmModePropertyPtr prop;
75 	int p;
76 
77 	for (p = 0; p < data->port_count; p++) {
78 		connector = chamelium_port_get_connector(data->chamelium,
79 							 data->ports[p], false);
80 
81 		igt_assert(kmstest_get_property(data->drm_fd,
82 						connector->connector_id,
83 						DRM_MODE_OBJECT_CONNECTOR,
84 						"link-status", NULL,
85 						&link_status, &prop));
86 
87 		link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD;
88 
89 		drmModeFreeProperty(prop);
90 		drmModeFreeConnector(connector);
91 	}
92 }
93 
94 static void
require_connector_present(data_t * data,unsigned int type)95 require_connector_present(data_t *data, unsigned int type)
96 {
97 	int i;
98 	bool found = false;
99 
100 	for (i = 0; i < data->port_count && !found; i++) {
101 		if (chamelium_port_get_type(data->ports[i]) == type)
102 			found = true;
103 	}
104 
105 	igt_require_f(found, "No port of type %s was found\n",
106 		      kmstest_connector_type_str(type));
107 }
108 
109 static drmModeConnection
reprobe_connector(data_t * data,struct chamelium_port * port)110 reprobe_connector(data_t *data, struct chamelium_port *port)
111 {
112 	drmModeConnector *connector;
113 	drmModeConnection status;
114 
115 	igt_debug("Reprobing %s...\n", chamelium_port_get_name(port));
116 	connector = chamelium_port_get_connector(data->chamelium, port, true);
117 	igt_assert(connector);
118 	status = connector->connection;
119 
120 	drmModeFreeConnector(connector);
121 	return status;
122 }
123 
connection_str(drmModeConnection c)124 static const char *connection_str(drmModeConnection c)
125 {
126 	switch (c) {
127 	case DRM_MODE_CONNECTED:
128 		return "connected";
129 	case DRM_MODE_DISCONNECTED:
130 		return "disconnected";
131 	case DRM_MODE_UNKNOWNCONNECTION:
132 		return "unknown";
133 	}
134 	assert(0); /* unreachable */
135 }
136 
137 static void
wait_for_connector(data_t * data,struct chamelium_port * port,drmModeConnection status)138 wait_for_connector(data_t *data, struct chamelium_port *port,
139 		   drmModeConnection status)
140 {
141 	igt_debug("Waiting for %s to get %s...\n",
142 		  chamelium_port_get_name(port), connection_str(status));
143 
144 	/*
145 	 * Rely on simple reprobing so we don't fail tests that don't require
146 	 * that hpd events work in the event that hpd doesn't work on the system
147 	 */
148 	igt_until_timeout(HOTPLUG_TIMEOUT) {
149 		if (reprobe_connector(data, port) == status) {
150 			return;
151 		}
152 
153 		usleep(50000);
154 	}
155 
156 	igt_assert_f(false, "Timed out waiting for %s to get %s\n",
157 		  chamelium_port_get_name(port), connection_str(status));
158 }
159 
160 static int chamelium_vga_modes[][2] = {
161 	{ 1600, 1200 },
162 	{ 1920, 1200 },
163 	{ 1920, 1080 },
164 	{ 1680, 1050 },
165 	{ 1280, 1024 },
166 	{ 1280, 960 },
167 	{ 1440, 900 },
168 	{ 1280, 800 },
169 	{ 1024, 768 },
170 	{ 1360, 768 },
171 	{ 1280, 720 },
172 	{ 800, 600 },
173 	{ 640, 480 },
174 	{ -1, -1 },
175 };
176 
177 static bool
prune_vga_mode(data_t * data,drmModeModeInfo * mode)178 prune_vga_mode(data_t *data, drmModeModeInfo *mode)
179 {
180 	int i = 0;
181 
182 	while (chamelium_vga_modes[i][0] != -1) {
183 		if (mode->hdisplay == chamelium_vga_modes[i][0] &&
184 		    mode->vdisplay == chamelium_vga_modes[i][1])
185 			return false;
186 
187 		i++;
188 	}
189 
190 	return true;
191 }
192 
193 static bool
check_analog_bridge(data_t * data,struct chamelium_port * port)194 check_analog_bridge(data_t *data, struct chamelium_port *port)
195 {
196 	drmModePropertyBlobPtr edid_blob = NULL;
197 	drmModeConnector *connector = chamelium_port_get_connector(
198 	    data->chamelium, port, false);
199 	uint64_t edid_blob_id;
200 	const struct edid *edid;
201 	char edid_vendor[3];
202 
203 	if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) {
204 		drmModeFreeConnector(connector);
205 		return false;
206 	}
207 
208 	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
209 					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
210 					&edid_blob_id, NULL));
211 	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
212 						      edid_blob_id));
213 
214 	edid = (const struct edid *) edid_blob->data;
215 	edid_get_mfg(edid, edid_vendor);
216 
217 	drmModeFreePropertyBlob(edid_blob);
218 	drmModeFreeConnector(connector);
219 
220 	/* Analog bridges provide their own EDID */
221 	if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' ||
222 	    edid_vendor[2] != 'T')
223 		return true;
224 
225 	return false;
226 }
227 
228 static void
reset_state(data_t * data,struct chamelium_port * port)229 reset_state(data_t *data, struct chamelium_port *port)
230 {
231 	int p;
232 
233 	chamelium_reset(data->chamelium);
234 
235 	if (port) {
236 		wait_for_connector(data, port, DRM_MODE_DISCONNECTED);
237 	} else {
238 		for (p = 0; p < data->port_count; p++) {
239 			port = data->ports[p];
240 			wait_for_connector(data, port, DRM_MODE_DISCONNECTED);
241 		}
242 	}
243 }
244 
245 static void
test_basic_hotplug(data_t * data,struct chamelium_port * port,int toggle_count)246 test_basic_hotplug(data_t *data, struct chamelium_port *port, int toggle_count)
247 {
248 	struct udev_monitor *mon = igt_watch_hotplug();
249 	int i;
250 	drmModeConnection status;
251 
252 	reset_state(data, NULL);
253 	igt_hpd_storm_set_threshold(data->drm_fd, 0);
254 
255 	for (i = 0; i < toggle_count; i++) {
256 		igt_flush_hotplugs(mon);
257 
258 		/* Check if we get a sysfs hotplug event */
259 		chamelium_plug(data->chamelium, port);
260 		igt_assert_f(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT),
261 			     "Timed out waiting for hotplug uevent\n");
262 		status = reprobe_connector(data, port);
263 		igt_assert_f(status == DRM_MODE_CONNECTED,
264 			     "Invalid connector status after hotplug: "
265 			     "got %s, expected connected\n",
266 			     connection_str(status));
267 
268 		igt_flush_hotplugs(mon);
269 
270 		/* Now check if we get a hotplug from disconnection */
271 		chamelium_unplug(data->chamelium, port);
272 		igt_assert_f(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT),
273 			     "Timed out waiting for unplug uevent\n");
274 		igt_assert_f(status == DRM_MODE_DISCONNECTED,
275 			     "Invalid connector status after hotplug: "
276 			     "got %s, expected disconnected\n",
277 			     connection_str(status));
278 	}
279 
280 	igt_cleanup_hotplug(mon);
281 	igt_hpd_storm_reset(data->drm_fd);
282 }
283 
284 static const struct edid *get_edid(enum test_edid edid);
285 
set_edid(data_t * data,struct chamelium_port * port,enum test_edid edid)286 static void set_edid(data_t *data, struct chamelium_port *port,
287 		     enum test_edid edid)
288 {
289 	chamelium_port_set_edid(data->chamelium, port, data->edids[edid]);
290 }
291 
292 static void
test_edid_read(data_t * data,struct chamelium_port * port,enum test_edid edid)293 test_edid_read(data_t *data, struct chamelium_port *port, enum test_edid edid)
294 {
295 	drmModePropertyBlobPtr edid_blob = NULL;
296 	drmModeConnector *connector = chamelium_port_get_connector(
297 	    data->chamelium, port, false);
298 	size_t raw_edid_size;
299 	const struct edid *raw_edid;
300 	uint64_t edid_blob_id;
301 
302 	reset_state(data, port);
303 
304 	set_edid(data, port, edid);
305 	chamelium_plug(data->chamelium, port);
306 	wait_for_connector(data, port, DRM_MODE_CONNECTED);
307 
308 	igt_skip_on(check_analog_bridge(data, port));
309 
310 	igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id,
311 					DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL,
312 					&edid_blob_id, NULL));
313 	igt_assert(edid_blob_id != 0);
314 	igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd,
315 						      edid_blob_id));
316 
317 	raw_edid = chamelium_edid_get_raw(data->edids[edid], port);
318 	raw_edid_size = edid_get_size(raw_edid);
319 	igt_assert(memcmp(raw_edid, edid_blob->data, raw_edid_size) == 0);
320 
321 	drmModeFreePropertyBlob(edid_blob);
322 	drmModeFreeConnector(connector);
323 }
324 
325 /* Wait for hotplug and return the remaining time left from timeout */
wait_for_hotplug(struct udev_monitor * mon,int * timeout)326 static bool wait_for_hotplug(struct udev_monitor *mon, int *timeout)
327 {
328 	struct timespec start, end;
329 	int elapsed;
330 	bool detected;
331 
332 	igt_assert_eq(igt_gettime(&start), 0);
333 	detected = igt_hotplug_detected(mon, *timeout);
334 	igt_assert_eq(igt_gettime(&end), 0);
335 
336 	elapsed = igt_time_elapsed(&start, &end);
337 	igt_assert_lte(0, elapsed);
338 	*timeout = max(0, *timeout - elapsed);
339 
340 	return detected;
341 }
342 
343 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)344 try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
345 		       enum igt_suspend_state state, enum igt_suspend_test test,
346 		       struct udev_monitor *mon, bool connected)
347 {
348 	drmModeConnection target_state = connected ? DRM_MODE_DISCONNECTED :
349 						     DRM_MODE_CONNECTED;
350 	int timeout = HOTPLUG_TIMEOUT;
351 	int delay;
352 	int p;
353 
354 	igt_flush_hotplugs(mon);
355 
356 	delay = igt_get_autoresume_delay(state) * 1000 / 2;
357 
358 	if (port) {
359 		chamelium_schedule_hpd_toggle(data->chamelium, port, delay,
360 					      !connected);
361 	} else {
362 		for (p = 0; p < data->port_count; p++) {
363 			port = data->ports[p];
364 			chamelium_schedule_hpd_toggle(data->chamelium, port,
365 						      delay, !connected);
366 		}
367 
368 		port = NULL;
369 	}
370 
371 	igt_system_suspend_autoresume(state, test);
372 	igt_assert(wait_for_hotplug(mon, &timeout));
373 	chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
374 
375 	if (port) {
376 		igt_assert_eq(reprobe_connector(data, port), target_state);
377 	} else {
378 		for (p = 0; p < data->port_count; p++) {
379 			drmModeConnection current_state;
380 
381 			port = data->ports[p];
382 			/*
383 			 * There could be as many hotplug events sent by
384 			 * driver as connectors we scheduled an HPD toggle on
385 			 * above, depending on timing. So if we're not seeing
386 			 * the expected connector state try to wait for an HPD
387 			 * event for each connector/port.
388 			 */
389 			current_state = reprobe_connector(data, port);
390 			if (p > 0 && current_state != target_state) {
391 				igt_assert(wait_for_hotplug(mon, &timeout));
392 				current_state = reprobe_connector(data, port);
393 			}
394 
395 			igt_assert_eq(current_state, target_state);
396 		}
397 
398 		port = NULL;
399 	}
400 }
401 
402 static void
test_suspend_resume_hpd(data_t * data,struct chamelium_port * port,enum igt_suspend_state state,enum igt_suspend_test test)403 test_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
404 			enum igt_suspend_state state,
405 			enum igt_suspend_test test)
406 {
407 	struct udev_monitor *mon = igt_watch_hotplug();
408 
409 	reset_state(data, port);
410 
411 	/* Make sure we notice new connectors after resuming */
412 	try_suspend_resume_hpd(data, port, state, test, mon, false);
413 
414 	/* Now make sure we notice disconnected connectors after resuming */
415 	try_suspend_resume_hpd(data, port, state, test, mon, true);
416 
417 	igt_cleanup_hotplug(mon);
418 }
419 
420 static void
test_suspend_resume_hpd_common(data_t * data,enum igt_suspend_state state,enum igt_suspend_test test)421 test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state,
422 			       enum igt_suspend_test test)
423 {
424 	struct udev_monitor *mon = igt_watch_hotplug();
425 	struct chamelium_port *port;
426 	int p;
427 
428 	for (p = 0; p < data->port_count; p++) {
429 		port = data->ports[p];
430 		igt_debug("Testing port %s\n", chamelium_port_get_name(port));
431 	}
432 
433 	reset_state(data, NULL);
434 
435 	/* Make sure we notice new connectors after resuming */
436 	try_suspend_resume_hpd(data, NULL, state, test, mon, false);
437 
438 	/* Now make sure we notice disconnected connectors after resuming */
439 	try_suspend_resume_hpd(data, NULL, state, test, mon, true);
440 
441 	igt_cleanup_hotplug(mon);
442 }
443 
444 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 test_edid edid,enum test_edid alt_edid)445 test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
446 				enum igt_suspend_state state,
447 				enum igt_suspend_test test,
448 				enum test_edid edid,
449 				enum test_edid alt_edid)
450 {
451 	struct udev_monitor *mon = igt_watch_hotplug();
452 	bool link_status_failed[2][data->port_count];
453 	int p;
454 
455 	reset_state(data, port);
456 
457 	/* Catch the event and flush all remaining ones. */
458 	igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
459 	igt_flush_hotplugs(mon);
460 
461 	/* First plug in the port */
462 	set_edid(data, port, edid);
463 	chamelium_plug(data->chamelium, port);
464 	igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
465 
466 	wait_for_connector(data, port, DRM_MODE_CONNECTED);
467 
468 	/*
469 	 * Change the edid before we suspend. On resume, the machine should
470 	 * notice the EDID change and fire a hotplug event.
471 	 */
472 	set_edid(data, port, alt_edid);
473 
474 	get_connectors_link_status_failed(data, link_status_failed[0]);
475 
476 	igt_flush_hotplugs(mon);
477 
478 	igt_system_suspend_autoresume(state, test);
479 	igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
480 	chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
481 
482 	get_connectors_link_status_failed(data, link_status_failed[1]);
483 
484 	for (p = 0; p < data->port_count; p++)
485 		igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]);
486 }
487 
488 static igt_output_t *
prepare_output(data_t * data,struct chamelium_port * port,enum test_edid edid)489 prepare_output(data_t *data, struct chamelium_port *port, enum test_edid edid)
490 {
491 	igt_display_t *display = &data->display;
492 	igt_output_t *output;
493 	drmModeConnector *connector =
494 		chamelium_port_get_connector(data->chamelium, port, false);
495 	enum pipe pipe;
496 	bool found = false;
497 
498 	/* The chamelium's default EDID has a lot of resolutions, way more then
499 	 * we need to test. Additionally the default EDID doesn't support HDMI
500 	 * audio.
501 	 */
502 	set_edid(data, port, edid);
503 
504 	chamelium_plug(data->chamelium, port);
505 	wait_for_connector(data, port, DRM_MODE_CONNECTED);
506 
507 	igt_display_reset(display);
508 
509 	output = igt_output_from_connector(display, connector);
510 
511 	/* Refresh pipe to update connected status */
512 	igt_output_set_pipe(output, PIPE_NONE);
513 
514 	for_each_pipe(display, pipe) {
515 		if (!igt_pipe_connector_valid(pipe, output))
516 			continue;
517 
518 		found = true;
519 		break;
520 	}
521 
522 	igt_assert_f(found, "No pipe found for output %s\n", igt_output_name(output));
523 
524 	igt_output_set_pipe(output, pipe);
525 
526 	drmModeFreeConnector(connector);
527 
528 	return output;
529 }
530 
531 static void
enable_output(data_t * data,struct chamelium_port * port,igt_output_t * output,drmModeModeInfo * mode,struct igt_fb * fb)532 enable_output(data_t *data,
533 	      struct chamelium_port *port,
534 	      igt_output_t *output,
535 	      drmModeModeInfo *mode,
536 	      struct igt_fb *fb)
537 {
538 	igt_display_t *display = output->display;
539 	igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
540 	drmModeConnector *connector = chamelium_port_get_connector(
541 	    data->chamelium, port, false);
542 
543 	igt_assert(primary);
544 
545 	igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay);
546 	igt_plane_set_fb(primary, fb);
547 	igt_output_override_mode(output, mode);
548 
549 	/* Clear any color correction values that might be enabled */
550 	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
551 		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0);
552 	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT))
553 		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0);
554 	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
555 		igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0);
556 
557 	igt_display_commit2(display, COMMIT_ATOMIC);
558 
559 	if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
560 		usleep(250000);
561 
562 	drmModeFreeConnector(connector);
563 }
564 
find_mode(const drmModeModeInfo * list,size_t list_len,const drmModeModeInfo * mode)565 static bool find_mode(const drmModeModeInfo *list, size_t list_len,
566 		      const drmModeModeInfo *mode)
567 {
568 	size_t i;
569 
570 	for (i = 0; i < list_len; i++) {
571 		if (memcmp(&list[i], mode, sizeof(*mode)) == 0) {
572 			return true;
573 		}
574 	}
575 
576 	return false;
577 }
578 
check_modes_subset(const drmModeModeInfo * prev,size_t prev_len,const drmModeModeInfo * cur,size_t cur_len)579 static void check_modes_subset(const drmModeModeInfo *prev, size_t prev_len,
580 			       const drmModeModeInfo *cur, size_t cur_len)
581 {
582 	size_t i;
583 
584 	for (i = 0; i < cur_len; i++) {
585 		igt_assert_f(find_mode(prev, prev_len, &cur[i]),
586 			     "Got new mode %s after link status failure\n",
587 			     cur[i].name);
588 	}
589 
590 	igt_assert(cur_len <= prev_len); /* safety net */
591 	igt_debug("New mode list contains %zu less modes\n",
592 		  prev_len - cur_len);
593 }
594 
are_fallback_modes(const drmModeModeInfo * modes,size_t modes_len)595 static bool are_fallback_modes(const drmModeModeInfo *modes, size_t modes_len)
596 {
597 	igt_assert(modes_len > 0);
598 
599 	return modes[0].hdisplay <= 1024 && modes[0].vdisplay <= 768;
600 }
601 
602 static void
test_link_status(data_t * data,struct chamelium_port * port)603 test_link_status(data_t *data, struct chamelium_port *port)
604 {
605 	drmModeConnector *connector;
606 	igt_output_t *output;
607 	igt_plane_t *primary;
608 	drmModeModeInfo *prev_modes;
609 	size_t prev_modes_len;
610 	drmModeModeInfo mode = {0};
611 	uint32_t link_status_id;
612 	uint64_t link_status;
613 	bool has_prop;
614 	unsigned int fb_id = 0;
615 	struct igt_fb fb;
616 	struct udev_monitor *mon;
617 
618 	igt_require(chamelium_supports_trigger_link_failure(data->chamelium));
619 
620 	reset_state(data, port);
621 
622 	output = prepare_output(data, port, TEST_EDID_BASE);
623 	connector = chamelium_port_get_connector(data->chamelium, port, false);
624 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
625 	igt_assert(primary);
626 
627 	has_prop = kmstest_get_property(data->drm_fd, connector->connector_id,
628 					DRM_MODE_OBJECT_CONNECTOR,
629 					"link-status", &link_status_id,
630 					&link_status, NULL);
631 	igt_require(has_prop);
632 	igt_assert_f(link_status == DRM_MODE_LINK_STATUS_GOOD,
633 		     "Expected link status to be %d initially, got %"PRIu64"\n",
634 		     DRM_MODE_LINK_STATUS_GOOD, link_status);
635 
636 	igt_debug("Connector has %d modes\n", connector->count_modes);
637 	prev_modes_len = connector->count_modes;
638 	prev_modes = malloc(prev_modes_len * sizeof(drmModeModeInfo));
639 	memcpy(prev_modes, connector->modes,
640 	       prev_modes_len * sizeof(drmModeModeInfo));
641 
642 	mon = igt_watch_hotplug();
643 
644 	while (1) {
645 		if (link_status == DRM_MODE_LINK_STATUS_BAD) {
646 			igt_output_set_prop_value(output,
647 						  IGT_CONNECTOR_LINK_STATUS,
648 						  DRM_MODE_LINK_STATUS_GOOD);
649 		}
650 
651 		if (memcmp(&connector->modes[0], &mode, sizeof(mode)) != 0) {
652 			igt_assert(connector->count_modes > 0);
653 			mode = connector->modes[0];
654 			igt_debug("Modesetting with %s\n", mode.name);
655 			if (fb_id > 0)
656 				igt_remove_fb(data->drm_fd, &fb);
657 			fb_id = igt_create_color_pattern_fb(data->drm_fd,
658 							    mode.hdisplay,
659 							    mode.vdisplay,
660 							    DRM_FORMAT_XRGB8888,
661 							    LOCAL_DRM_FORMAT_MOD_NONE,
662 							    0, 0, 0, &fb);
663 			igt_assert(fb_id > 0);
664 			enable_output(data, port, output, &mode, &fb);
665 		} else {
666 			igt_display_commit2(&data->display, COMMIT_ATOMIC);
667 		}
668 
669 		igt_debug("Triggering link failure\n");
670 		chamelium_trigger_link_failure(data->chamelium, port);
671 
672 		igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
673 		igt_assert_eq(reprobe_connector(data, port),
674 			      DRM_MODE_CONNECTED);
675 
676 		igt_flush_hotplugs(mon);
677 
678 		drmModeFreeConnector(connector);
679 		connector = chamelium_port_get_connector(data->chamelium, port,
680 							 false);
681 		link_status = igt_output_get_prop(output, IGT_CONNECTOR_LINK_STATUS);
682 		igt_assert_f(link_status == DRM_MODE_LINK_STATUS_BAD,
683 			     "Expected link status to be %d after link failure, "
684 			     "got %"PRIu64"\n",
685 			     DRM_MODE_LINK_STATUS_BAD, link_status);
686 		check_modes_subset(prev_modes, prev_modes_len,
687 				   connector->modes, connector->count_modes);
688 		prev_modes_len = connector->count_modes;
689 		memcpy(prev_modes, connector->modes,
690 		       connector->count_modes * sizeof(drmModeModeInfo));
691 
692 		if (are_fallback_modes(connector->modes, connector->count_modes)) {
693 			igt_debug("Reached fallback modes\n");
694 			break;
695 		}
696 	}
697 
698 	igt_cleanup_hotplug(mon);
699 	igt_remove_fb(data->drm_fd, &fb);
700 	free(prev_modes);
701 	drmModeFreeConnector(connector);
702 }
703 
chamelium_paint_xr24_pattern(uint32_t * data,size_t width,size_t height,size_t stride,size_t block_size)704 static void chamelium_paint_xr24_pattern(uint32_t *data,
705 					 size_t width, size_t height,
706 					 size_t stride, size_t block_size)
707 {
708 	uint32_t colors[] = { 0xff000000,
709 			      0xffff0000,
710 			      0xff00ff00,
711 			      0xff0000ff,
712 			      0xffffffff };
713 	unsigned i, j;
714 
715 	for (i = 0; i < height; i++)
716 		for (j = 0; j < width; j++)
717 			*(data + i * stride / 4 + j) = colors[((j / block_size) + (i / block_size)) % 5];
718 }
719 
chamelium_get_pattern_fb(data_t * data,size_t width,size_t height,uint32_t fourcc,size_t block_size,struct igt_fb * fb)720 static int chamelium_get_pattern_fb(data_t *data, size_t width, size_t height,
721 				    uint32_t fourcc, size_t block_size,
722 				    struct igt_fb *fb)
723 {
724 	int fb_id;
725 	void *ptr;
726 
727 	igt_assert(fourcc == DRM_FORMAT_XRGB8888);
728 
729 	fb_id = igt_create_fb(data->drm_fd, width, height, fourcc,
730 			      LOCAL_DRM_FORMAT_MOD_NONE, fb);
731 	igt_assert(fb_id > 0);
732 
733 	ptr = igt_fb_map_buffer(fb->fd, fb);
734 	igt_assert(ptr);
735 
736 	chamelium_paint_xr24_pattern(ptr, width, height, fb->strides[0],
737 				     block_size);
738 	igt_fb_unmap_buffer(fb, ptr);
739 
740 	return fb_id;
741 }
742 
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)743 static void do_test_display(data_t *data, struct chamelium_port *port,
744 			    igt_output_t *output, drmModeModeInfo *mode,
745 			    uint32_t fourcc, enum chamelium_check check,
746 			    int count)
747 {
748 	struct chamelium_fb_crc_async_data *fb_crc;
749 	struct igt_fb frame_fb, fb;
750 	int i, fb_id, captured_frame_count;
751 	int frame_id;
752 
753 	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
754 					 DRM_FORMAT_XRGB8888, 64, &fb);
755 	igt_assert(fb_id > 0);
756 
757 	frame_id = igt_fb_convert(&frame_fb, &fb, fourcc,
758 				  LOCAL_DRM_FORMAT_MOD_NONE);
759 	igt_assert(frame_id > 0);
760 
761 	if (check == CHAMELIUM_CHECK_CRC)
762 		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
763 								&fb);
764 
765 	enable_output(data, port, output, mode, &frame_fb);
766 
767 	if (check == CHAMELIUM_CHECK_CRC) {
768 		igt_crc_t *expected_crc;
769 		igt_crc_t *crc;
770 
771 		/* We want to keep the display running for a little bit, since
772 		 * there's always the potential the driver isn't able to keep
773 		 * the display running properly for very long
774 		 */
775 		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
776 		crc = chamelium_read_captured_crcs(data->chamelium,
777 						   &captured_frame_count);
778 
779 		igt_assert(captured_frame_count == count);
780 
781 		igt_debug("Captured %d frames\n", captured_frame_count);
782 
783 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
784 
785 		for (i = 0; i < captured_frame_count; i++)
786 			chamelium_assert_crc_eq_or_dump(data->chamelium,
787 							expected_crc, &crc[i],
788 							&fb, i);
789 
790 		free(expected_crc);
791 		free(crc);
792 	} else if (check == CHAMELIUM_CHECK_ANALOG ||
793 		   check == CHAMELIUM_CHECK_CHECKERBOARD) {
794 		struct chamelium_frame_dump *dump;
795 
796 		igt_assert(count == 1);
797 
798 		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
799 						  0, 0);
800 
801 		if (check == CHAMELIUM_CHECK_ANALOG)
802 			chamelium_crop_analog_frame(dump, mode->hdisplay,
803 						    mode->vdisplay);
804 
805 		chamelium_assert_frame_match_or_dump(data->chamelium, port,
806 						     dump, &fb, check);
807 		chamelium_destroy_frame_dump(dump);
808 	}
809 
810 	igt_remove_fb(data->drm_fd, &frame_fb);
811 	igt_remove_fb(data->drm_fd, &fb);
812 }
813 
test_display_one_mode(data_t * data,struct chamelium_port * port,uint32_t fourcc,enum chamelium_check check,int count)814 static void test_display_one_mode(data_t *data, struct chamelium_port *port,
815 				  uint32_t fourcc, enum chamelium_check check,
816 				  int count)
817 {
818 	drmModeConnector *connector;
819 	drmModeModeInfo *mode;
820 	igt_output_t *output;
821 	igt_plane_t *primary;
822 
823 	reset_state(data, port);
824 
825 	output = prepare_output(data, port, TEST_EDID_BASE);
826 	connector = chamelium_port_get_connector(data->chamelium, port, false);
827 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
828 	igt_assert(primary);
829 
830 	igt_require(igt_plane_has_format_mod(primary, fourcc, LOCAL_DRM_FORMAT_MOD_NONE));
831 
832 	mode = &connector->modes[0];
833 	if (check == CHAMELIUM_CHECK_ANALOG) {
834 		bool bridge = check_analog_bridge(data, port);
835 
836 		igt_assert(!(bridge && prune_vga_mode(data, mode)));
837 	}
838 
839 	do_test_display(data, port, output, mode, fourcc, check, count);
840 
841 	drmModeFreeConnector(connector);
842 }
843 
test_display_all_modes(data_t * data,struct chamelium_port * port,uint32_t fourcc,enum chamelium_check check,int count)844 static void test_display_all_modes(data_t *data, struct chamelium_port *port,
845 				   uint32_t fourcc, enum chamelium_check check,
846 				   int count)
847 {
848 	igt_output_t *output;
849 	igt_plane_t *primary;
850 	drmModeConnector *connector;
851 	bool bridge;
852 	int i;
853 
854 	reset_state(data, port);
855 
856 	output = prepare_output(data, port, TEST_EDID_BASE);
857 	connector = chamelium_port_get_connector(data->chamelium, port, false);
858 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
859 	igt_assert(primary);
860 	igt_require(igt_plane_has_format_mod(primary, fourcc, LOCAL_DRM_FORMAT_MOD_NONE));
861 
862 	if (check == CHAMELIUM_CHECK_ANALOG)
863 		bridge = check_analog_bridge(data, port);
864 
865 	for (i = 0; i < connector->count_modes; i++) {
866 		drmModeModeInfo *mode = &connector->modes[i];
867 
868 		if (check == CHAMELIUM_CHECK_ANALOG && bridge &&
869 		    prune_vga_mode(data, mode))
870 			continue;
871 
872 		do_test_display(data, port, output, mode, fourcc, check, count);
873 	}
874 
875 	drmModeFreeConnector(connector);
876 }
877 
878 static void
test_display_frame_dump(data_t * data,struct chamelium_port * port)879 test_display_frame_dump(data_t *data, struct chamelium_port *port)
880 {
881 	igt_output_t *output;
882 	igt_plane_t *primary;
883 	struct igt_fb fb;
884 	struct chamelium_frame_dump *frame;
885 	drmModeModeInfo *mode;
886 	drmModeConnector *connector;
887 	int fb_id, i, j;
888 
889 	reset_state(data, port);
890 
891 	output = prepare_output(data, port, TEST_EDID_BASE);
892 	connector = chamelium_port_get_connector(data->chamelium, port, false);
893 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
894 	igt_assert(primary);
895 
896 	for (i = 0; i < connector->count_modes; i++) {
897 		mode = &connector->modes[i];
898 		fb_id = igt_create_color_pattern_fb(data->drm_fd,
899 						    mode->hdisplay, mode->vdisplay,
900 						    DRM_FORMAT_XRGB8888,
901 						    LOCAL_DRM_FORMAT_MOD_NONE,
902 						    0, 0, 0, &fb);
903 		igt_assert(fb_id > 0);
904 
905 		enable_output(data, port, output, mode, &fb);
906 
907 		igt_debug("Reading frame dumps from Chamelium...\n");
908 		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
909 		for (j = 0; j < 5; j++) {
910 			frame = chamelium_read_captured_frame(
911 			    data->chamelium, j);
912 			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
913 			chamelium_destroy_frame_dump(frame);
914 		}
915 
916 		igt_remove_fb(data->drm_fd, &fb);
917 	}
918 
919 	drmModeFreeConnector(connector);
920 }
921 
922 #define MODE_CLOCK_ACCURACY 0.05 /* 5% */
923 
check_mode(struct chamelium * chamelium,struct chamelium_port * port,drmModeModeInfo * mode)924 static void check_mode(struct chamelium *chamelium, struct chamelium_port *port,
925 		       drmModeModeInfo *mode)
926 {
927 	struct chamelium_video_params video_params = {0};
928 	double mode_clock;
929 	int mode_hsync_offset, mode_vsync_offset;
930 	int mode_hsync_width, mode_vsync_width;
931 	int mode_hsync_polarity, mode_vsync_polarity;
932 
933 	chamelium_port_get_video_params(chamelium, port, &video_params);
934 
935 	mode_clock = (double) mode->clock / 1000;
936 	mode_hsync_offset = mode->hsync_start - mode->hdisplay;
937 	mode_vsync_offset = mode->vsync_start - mode->vdisplay;
938 	mode_hsync_width = mode->hsync_end - mode->hsync_start;
939 	mode_vsync_width = mode->vsync_end - mode->vsync_start;
940 	mode_hsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
941 	mode_vsync_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
942 
943 	igt_debug("Checking video mode:\n");
944 	igt_debug("clock: got %f, expected %f ± %f%%\n",
945 		  video_params.clock, mode_clock, MODE_CLOCK_ACCURACY * 100);
946 	igt_debug("hactive: got %d, expected %d\n",
947 		  video_params.hactive, mode->hdisplay);
948 	igt_debug("vactive: got %d, expected %d\n",
949 		  video_params.vactive, mode->vdisplay);
950 	igt_debug("hsync_offset: got %d, expected %d\n",
951 		  video_params.hsync_offset, mode_hsync_offset);
952 	igt_debug("vsync_offset: got %d, expected %d\n",
953 		  video_params.vsync_offset, mode_vsync_offset);
954 	igt_debug("htotal: got %d, expected %d\n",
955 		  video_params.htotal, mode->htotal);
956 	igt_debug("vtotal: got %d, expected %d\n",
957 		  video_params.vtotal, mode->vtotal);
958 	igt_debug("hsync_width: got %d, expected %d\n",
959 		  video_params.hsync_width, mode_hsync_width);
960 	igt_debug("vsync_width: got %d, expected %d\n",
961 		  video_params.vsync_width, mode_vsync_width);
962 	igt_debug("hsync_polarity: got %d, expected %d\n",
963 		  video_params.hsync_polarity, mode_hsync_polarity);
964 	igt_debug("vsync_polarity: got %d, expected %d\n",
965 		  video_params.vsync_polarity, mode_vsync_polarity);
966 
967 	if (!isnan(video_params.clock)) {
968 		igt_assert(video_params.clock >
969 			   mode_clock * (1 - MODE_CLOCK_ACCURACY));
970 		igt_assert(video_params.clock <
971 			   mode_clock * (1 + MODE_CLOCK_ACCURACY));
972 	}
973 	igt_assert(video_params.hactive == mode->hdisplay);
974 	igt_assert(video_params.vactive == mode->vdisplay);
975 	igt_assert(video_params.hsync_offset == mode_hsync_offset);
976 	igt_assert(video_params.vsync_offset == mode_vsync_offset);
977 	igt_assert(video_params.htotal == mode->htotal);
978 	igt_assert(video_params.vtotal == mode->vtotal);
979 	igt_assert(video_params.hsync_width == mode_hsync_width);
980 	igt_assert(video_params.vsync_width == mode_vsync_width);
981 	igt_assert(video_params.hsync_polarity == mode_hsync_polarity);
982 	igt_assert(video_params.vsync_polarity == mode_vsync_polarity);
983 }
984 
test_mode_timings(data_t * data,struct chamelium_port * port)985 static void test_mode_timings(data_t *data, struct chamelium_port *port)
986 {
987 	igt_output_t *output;
988 	igt_plane_t *primary;
989 	drmModeConnector *connector;
990 	int fb_id, i;
991 	struct igt_fb fb;
992 
993 	igt_require(chamelium_supports_get_video_params(data->chamelium));
994 
995 	reset_state(data, port);
996 
997 	output = prepare_output(data, port, TEST_EDID_BASE);
998 	connector = chamelium_port_get_connector(data->chamelium, port, false);
999 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
1000 	igt_assert(primary);
1001 
1002 	igt_assert(connector->count_modes > 0);
1003 	for (i = 0; i < connector->count_modes; i++) {
1004 		drmModeModeInfo *mode = &connector->modes[i];
1005 
1006 		fb_id = igt_create_color_pattern_fb(data->drm_fd,
1007 						    mode->hdisplay, mode->vdisplay,
1008 						    DRM_FORMAT_XRGB8888,
1009 						    LOCAL_DRM_FORMAT_MOD_NONE,
1010 						    0, 0, 0, &fb);
1011 		igt_assert(fb_id > 0);
1012 
1013 		enable_output(data, port, output, mode, &fb);
1014 
1015 		/* Trigger the FSM */
1016 		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 0);
1017 
1018 		check_mode(data->chamelium, port, mode);
1019 
1020 		igt_remove_fb(data->drm_fd, &fb);
1021 	}
1022 
1023 	drmModeFreeConnector(connector);
1024 }
1025 
1026 /* Set of Video Identification Codes advertised in the EDID */
1027 static const uint8_t edid_ar_svds[] = {
1028 	16, /* 1080p @ 60Hz, 16:9 */
1029 };
1030 
1031 struct vic_mode {
1032 	int hactive, vactive;
1033 	int vrefresh; /* Hz */
1034 	uint32_t picture_ar;
1035 };
1036 
1037 /* Maps Video Identification Codes to a mode */
1038 static const struct vic_mode vic_modes[] = {
1039 	[16] = {
1040 		.hactive = 1920,
1041 		.vactive = 1080,
1042 		.vrefresh = 60,
1043 		.picture_ar = DRM_MODE_PICTURE_ASPECT_16_9,
1044 	},
1045 };
1046 
1047 /* Maps aspect ratios to their mode flag */
1048 static const uint32_t mode_ar_flags[] = {
1049 	[DRM_MODE_PICTURE_ASPECT_16_9] = DRM_MODE_FLAG_PIC_AR_16_9,
1050 };
1051 
1052 static enum infoframe_avi_picture_aspect_ratio
get_infoframe_avi_picture_ar(uint32_t aspect_ratio)1053 get_infoframe_avi_picture_ar(uint32_t aspect_ratio)
1054 {
1055 	/* The AVI picture aspect ratio field only supports 4:3 and 16:9 */
1056 	switch (aspect_ratio) {
1057 	case DRM_MODE_PICTURE_ASPECT_4_3:
1058 		return INFOFRAME_AVI_PIC_AR_4_3;
1059 	case DRM_MODE_PICTURE_ASPECT_16_9:
1060 		return INFOFRAME_AVI_PIC_AR_16_9;
1061 	default:
1062 		return INFOFRAME_AVI_PIC_AR_UNSPECIFIED;
1063 	}
1064 }
1065 
vic_mode_matches_drm(const struct vic_mode * vic_mode,drmModeModeInfo * drm_mode)1066 static bool vic_mode_matches_drm(const struct vic_mode *vic_mode,
1067 				 drmModeModeInfo *drm_mode)
1068 {
1069 	uint32_t ar_flag = mode_ar_flags[vic_mode->picture_ar];
1070 
1071 	return vic_mode->hactive == drm_mode->hdisplay &&
1072 	       vic_mode->vactive == drm_mode->vdisplay &&
1073 	       vic_mode->vrefresh == drm_mode->vrefresh &&
1074 	       ar_flag == (drm_mode->flags & DRM_MODE_FLAG_PIC_AR_MASK);
1075 }
1076 
get_aspect_ratio_edid(void)1077 static const struct edid *get_aspect_ratio_edid(void)
1078 {
1079 	static unsigned char raw_edid[2 * EDID_BLOCK_SIZE] = {0};
1080 	struct edid *edid;
1081 	struct edid_ext *edid_ext;
1082 	struct edid_cea *edid_cea;
1083 	char *cea_data;
1084 	struct edid_cea_data_block *block;
1085 	size_t cea_data_size = 0, vsdb_size;
1086 	const struct cea_vsdb *vsdb;
1087 
1088 	edid = (struct edid *) raw_edid;
1089 	memcpy(edid, igt_kms_get_base_edid(), sizeof(struct edid));
1090 	edid->extensions_len = 1;
1091 	edid_ext = &edid->extensions[0];
1092 	edid_cea = &edid_ext->data.cea;
1093 	cea_data = edid_cea->data;
1094 
1095 	/* The HDMI VSDB advertises support for InfoFrames */
1096 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
1097 	vsdb = cea_vsdb_get_hdmi_default(&vsdb_size);
1098 	cea_data_size += edid_cea_data_block_set_vsdb(block, vsdb,
1099 						      vsdb_size);
1100 
1101 	/* Short Video Descriptor */
1102 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
1103 	cea_data_size += edid_cea_data_block_set_svd(block, edid_ar_svds,
1104 						     sizeof(edid_ar_svds));
1105 
1106 	assert(cea_data_size <= sizeof(edid_cea->data));
1107 
1108 	edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
1109 
1110 	edid_update_checksum(edid);
1111 
1112 	return edid;
1113 }
1114 
test_display_aspect_ratio(data_t * data,struct chamelium_port * port)1115 static void test_display_aspect_ratio(data_t *data, struct chamelium_port *port)
1116 {
1117 	igt_output_t *output;
1118 	igt_plane_t *primary;
1119 	drmModeConnector *connector;
1120 	drmModeModeInfo *mode;
1121 	int fb_id, i;
1122 	struct igt_fb fb;
1123 	bool found, ok;
1124 	struct chamelium_infoframe *infoframe;
1125 	struct infoframe_avi infoframe_avi;
1126 	uint8_t vic = 16; /* TODO: test more VICs */
1127 	const struct vic_mode *vic_mode;
1128 	uint32_t aspect_ratio;
1129 	enum infoframe_avi_picture_aspect_ratio frame_ar;
1130 
1131 	igt_require(chamelium_supports_get_last_infoframe(data->chamelium));
1132 
1133 	reset_state(data, port);
1134 
1135 	output = prepare_output(data, port, TEST_EDID_ASPECT_RATIO);
1136 	connector = chamelium_port_get_connector(data->chamelium, port, false);
1137 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
1138 	igt_assert(primary);
1139 
1140 	vic_mode = &vic_modes[vic];
1141 	aspect_ratio = vic_mode->picture_ar;
1142 
1143 	found = false;
1144 	igt_assert(connector->count_modes > 0);
1145 	for (i = 0; i < connector->count_modes; i++) {
1146 		mode = &connector->modes[i];
1147 
1148 		if (vic_mode_matches_drm(vic_mode, mode)) {
1149 			found = true;
1150 			break;
1151 		}
1152 	}
1153 	igt_assert_f(found,
1154 		     "Failed to find mode with the correct aspect ratio\n");
1155 
1156 	fb_id = igt_create_color_pattern_fb(data->drm_fd,
1157 					    mode->hdisplay, mode->vdisplay,
1158 					    DRM_FORMAT_XRGB8888,
1159 					    LOCAL_DRM_FORMAT_MOD_NONE,
1160 					    0, 0, 0, &fb);
1161 	igt_assert(fb_id > 0);
1162 
1163 	enable_output(data, port, output, mode, &fb);
1164 
1165 	infoframe = chamelium_get_last_infoframe(data->chamelium, port,
1166 						 CHAMELIUM_INFOFRAME_AVI);
1167 	igt_assert_f(infoframe, "AVI InfoFrame not received\n");
1168 
1169 	ok = infoframe_avi_parse(&infoframe_avi, infoframe->version,
1170 				 infoframe->payload, infoframe->payload_size);
1171 	igt_assert_f(ok, "Failed to parse AVI InfoFrame\n");
1172 
1173 	frame_ar = get_infoframe_avi_picture_ar(aspect_ratio);
1174 
1175 	igt_debug("Checking AVI InfoFrame\n");
1176 	igt_debug("Picture aspect ratio: got %d, expected %d\n",
1177 		  infoframe_avi.picture_aspect_ratio, frame_ar);
1178 	igt_debug("Video Identification Code (VIC): got %d, expected %d\n",
1179 		  infoframe_avi.vic, vic);
1180 
1181 	igt_assert(infoframe_avi.picture_aspect_ratio == frame_ar);
1182 	igt_assert(infoframe_avi.vic == vic);
1183 
1184 	chamelium_infoframe_destroy(infoframe);
1185 	igt_remove_fb(data->drm_fd, &fb);
1186 	drmModeFreeConnector(connector);
1187 }
1188 
1189 
1190 /* Playback parameters control the audio signal we synthesize and send */
1191 #define PLAYBACK_CHANNELS 2
1192 #define PLAYBACK_SAMPLES 1024
1193 
1194 /* Capture paremeters control the audio signal we receive */
1195 #define CAPTURE_SAMPLES 2048
1196 
1197 #define AUDIO_TIMEOUT 2000 /* ms */
1198 /* A streak of 3 gives confidence that the signal is good. */
1199 #define MIN_STREAK 3
1200 
1201 #define FLATLINE_AMPLITUDE 0.1 /* normalized, ie. in [0, 1] */
1202 #define FLATLINE_AMPLITUDE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
1203 #define FLATLINE_ALIGN_ACCURACY 0 /* number of samples */
1204 
1205 /* TODO: enable >48KHz rates, these are not reliable */
1206 static int test_sampling_rates[] = {
1207 	32000,
1208 	44100,
1209 	48000,
1210 	/* 88200, */
1211 	/* 96000, */
1212 	/* 176400, */
1213 	/* 192000, */
1214 };
1215 
1216 static int test_sampling_rates_count = sizeof(test_sampling_rates) / sizeof(int);
1217 
1218 /* Test frequencies (Hz): a sine signal will be generated for each.
1219  *
1220  * Depending on the sampling rate chosen, it might not be possible to properly
1221  * detect the generated sine (see Nyquist–Shannon sampling theorem).
1222  * Frequencies that can't be reliably detected will be automatically pruned in
1223  * #audio_signal_add_frequency. For instance, the 80KHz frequency can only be
1224  * tested with a 192KHz sampling rate.
1225  */
1226 static int test_frequencies[] = {
1227 	300,
1228 	600,
1229 	1200,
1230 	10000,
1231 	80000,
1232 };
1233 
1234 static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
1235 
1236 static const snd_pcm_format_t test_formats[] = {
1237 	SND_PCM_FORMAT_S16_LE,
1238 	SND_PCM_FORMAT_S24_LE,
1239 	SND_PCM_FORMAT_S32_LE,
1240 };
1241 
1242 static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
1243 
1244 struct audio_state {
1245 	struct alsa *alsa;
1246 	struct chamelium *chamelium;
1247 	struct chamelium_port *port;
1248 	struct chamelium_stream *stream;
1249 
1250 	/* The capture format is only available after capture has started. */
1251 	struct {
1252 		snd_pcm_format_t format;
1253 		int channels;
1254 		int rate;
1255 	} playback, capture;
1256 
1257 	char *name;
1258 	struct audio_signal *signal; /* for frequencies test only */
1259 	int channel_mapping[CHAMELIUM_MAX_AUDIO_CHANNELS];
1260 
1261 	size_t recv_pages;
1262 	int msec;
1263 
1264 	int dump_fd;
1265 	char *dump_path;
1266 
1267 	pthread_t thread;
1268 	atomic_bool run;
1269 	atomic_bool positive; /* for pulse test only */
1270 };
1271 
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)1272 static void audio_state_init(struct audio_state *state, data_t *data,
1273 			     struct alsa *alsa, struct chamelium_port *port,
1274 			     snd_pcm_format_t format, int channels, int rate)
1275 {
1276 	memset(state, 0, sizeof(*state));
1277 	state->dump_fd = -1;
1278 
1279 	state->alsa = alsa;
1280 	state->chamelium = data->chamelium;
1281 	state->port = port;
1282 
1283 	state->playback.format = format;
1284 	state->playback.channels = channels;
1285 	state->playback.rate = rate;
1286 
1287 	alsa_configure_output(alsa, format, channels, rate);
1288 
1289 	state->stream = chamelium_stream_init();
1290 	igt_assert_f(state->stream,
1291 		     "Failed to initialize Chamelium stream client\n");
1292 }
1293 
audio_state_fini(struct audio_state * state)1294 static void audio_state_fini(struct audio_state *state)
1295 {
1296 	chamelium_stream_deinit(state->stream);
1297 	free(state->name);
1298 }
1299 
run_audio_thread(void * data)1300 static void *run_audio_thread(void *data)
1301 {
1302 	struct alsa *alsa = data;
1303 
1304 	alsa_run(alsa, -1);
1305 	return NULL;
1306 }
1307 
audio_state_start(struct audio_state * state,const char * name)1308 static void audio_state_start(struct audio_state *state, const char *name)
1309 {
1310 	int ret;
1311 	bool ok;
1312 	size_t i, j;
1313 	enum chamelium_stream_realtime_mode stream_mode;
1314 	char dump_suffix[64];
1315 
1316 	free(state->name);
1317 	state->name = strdup(name);
1318 	state->recv_pages = 0;
1319 	state->msec = 0;
1320 
1321 	igt_debug("Starting %s test with playback format %s, "
1322 		  "sampling rate %d Hz and %d channels\n",
1323 		  name, snd_pcm_format_name(state->playback.format),
1324 		  state->playback.rate, state->playback.channels);
1325 
1326 	chamelium_start_capturing_audio(state->chamelium, state->port, false);
1327 
1328 	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
1329 	ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
1330 	igt_assert_f(ok, "Failed to start streaming audio capture\n");
1331 
1332 	/* Start playing audio */
1333 	state->run = true;
1334 	ret = pthread_create(&state->thread, NULL,
1335 			     run_audio_thread, state->alsa);
1336 	igt_assert_f(ret == 0, "Failed to start audio playback thread\n");
1337 
1338 	/* The Chamelium device only supports this PCM format. */
1339 	state->capture.format = SND_PCM_FORMAT_S32_LE;
1340 
1341 	/* Only after we've started playing audio, we can retrieve the capture
1342 	 * format used by the Chamelium device. */
1343 	chamelium_get_audio_format(state->chamelium, state->port,
1344 				   &state->capture.rate,
1345 				   &state->capture.channels);
1346 	if (state->capture.rate == 0) {
1347 		igt_debug("Audio receiver doesn't indicate the capture "
1348 			 "sampling rate, assuming it's %d Hz\n",
1349 			 state->playback.rate);
1350 		state->capture.rate = state->playback.rate;
1351 	}
1352 
1353 	chamelium_get_audio_channel_mapping(state->chamelium, state->port,
1354 					    state->channel_mapping);
1355 	/* Make sure we can capture all channels we send. */
1356 	for (i = 0; i < state->playback.channels; i++) {
1357 		ok = false;
1358 		for (j = 0; j < state->capture.channels; j++) {
1359 			if (state->channel_mapping[j] == i) {
1360 				ok = true;
1361 				break;
1362 			}
1363 		}
1364 		igt_assert_f(ok, "Cannot capture all channels\n");
1365 	}
1366 
1367 	if (igt_frame_dump_is_enabled()) {
1368 		snprintf(dump_suffix, sizeof(dump_suffix),
1369 			 "capture-%s-%s-%dch-%dHz",
1370 			 name, snd_pcm_format_name(state->playback.format),
1371 			 state->playback.channels, state->playback.rate);
1372 
1373 		state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
1374 							      state->capture.rate,
1375 							      state->capture.channels,
1376 							      &state->dump_path);
1377 		igt_assert_f(state->dump_fd >= 0,
1378 			     "Failed to create audio dump file\n");
1379 	}
1380 }
1381 
audio_state_receive(struct audio_state * state,int32_t ** recv,size_t * recv_len)1382 static void audio_state_receive(struct audio_state *state,
1383 				int32_t **recv, size_t *recv_len)
1384 {
1385 	bool ok;
1386 	size_t page_count;
1387 	size_t recv_size;
1388 
1389 	ok = chamelium_stream_receive_realtime_audio(state->stream,
1390 						     &page_count,
1391 						     recv, recv_len);
1392 	igt_assert_f(ok, "Failed to receive audio from stream server\n");
1393 
1394 	state->msec = state->recv_pages * *recv_len
1395 		      / (double) state->capture.channels
1396 		      / (double) state->capture.rate * 1000;
1397 	state->recv_pages++;
1398 
1399 	if (state->dump_fd >= 0) {
1400 		recv_size = *recv_len * sizeof(int32_t);
1401 		igt_assert_f(write(state->dump_fd, *recv, recv_size) == recv_size,
1402 			     "Failed to write to audio dump file\n");
1403 	}
1404 }
1405 
audio_state_stop(struct audio_state * state,bool success)1406 static void audio_state_stop(struct audio_state *state, bool success)
1407 {
1408 	bool ok;
1409 	int ret;
1410 	struct chamelium_audio_file *audio_file;
1411 
1412 	igt_debug("Stopping audio playback\n");
1413 	state->run = false;
1414 	ret = pthread_join(state->thread, NULL);
1415 	igt_assert_f(ret == 0, "Failed to join audio playback thread\n");
1416 
1417 	ok = chamelium_stream_stop_realtime_audio(state->stream);
1418 	igt_assert_f(ok, "Failed to stop streaming audio capture\n");
1419 
1420 	audio_file = chamelium_stop_capturing_audio(state->chamelium,
1421 						    state->port);
1422 	if (audio_file) {
1423 		igt_debug("Audio file saved on the Chamelium in %s\n",
1424 			  audio_file->path);
1425 		chamelium_destroy_audio_file(audio_file);
1426 	}
1427 
1428 	if (state->dump_fd >= 0) {
1429 		close(state->dump_fd);
1430 		state->dump_fd = -1;
1431 
1432 		if (success) {
1433 			/* Test succeeded, no need to keep the captured data */
1434 			unlink(state->dump_path);
1435 		} else
1436 			igt_debug("Saved captured audio data to %s\n",
1437 				  state->dump_path);
1438 		free(state->dump_path);
1439 		state->dump_path = NULL;
1440 	}
1441 
1442 	igt_debug("Audio %s test result for format %s, sampling rate %d Hz "
1443 		  "and %d channels: %s\n",
1444 		  state->name, snd_pcm_format_name(state->playback.format),
1445 		  state->playback.rate, state->playback.channels,
1446 		  success ? "ALL GREEN" : "FAILED");
1447 }
1448 
check_audio_infoframe(struct audio_state * state)1449 static void check_audio_infoframe(struct audio_state *state)
1450 {
1451 	struct chamelium_infoframe *infoframe;
1452 	struct infoframe_audio infoframe_audio;
1453 	struct infoframe_audio expected = {0};
1454 	bool ok;
1455 
1456 	if (!chamelium_supports_get_last_infoframe(state->chamelium)) {
1457 		igt_debug("Skipping audio InfoFrame check: "
1458 			  "Chamelium board doesn't support GetLastInfoFrame\n");
1459 		return;
1460 	}
1461 
1462 	expected.coding_type = INFOFRAME_AUDIO_CT_PCM;
1463 	expected.channel_count = state->playback.channels;
1464 	expected.sampling_freq = state->playback.rate;
1465 	expected.sample_size = snd_pcm_format_width(state->playback.format);
1466 
1467 	infoframe = chamelium_get_last_infoframe(state->chamelium, state->port,
1468 						 CHAMELIUM_INFOFRAME_AUDIO);
1469 	if (infoframe == NULL && state->playback.channels <= 2) {
1470 		/* Audio InfoFrames are optional for mono and stereo audio */
1471 		igt_debug("Skipping audio InfoFrame check: "
1472 			  "no InfoFrame received\n");
1473 		return;
1474 	}
1475 	igt_assert_f(infoframe != NULL, "no audio InfoFrame received\n");
1476 
1477 	ok = infoframe_audio_parse(&infoframe_audio, infoframe->version,
1478 				   infoframe->payload, infoframe->payload_size);
1479 	chamelium_infoframe_destroy(infoframe);
1480 	igt_assert_f(ok, "failed to parse audio InfoFrame\n");
1481 
1482 	igt_debug("Checking audio InfoFrame:\n");
1483 	igt_debug("coding_type: got %d, expected %d\n",
1484 		  infoframe_audio.coding_type, expected.coding_type);
1485 	igt_debug("channel_count: got %d, expected %d\n",
1486 		  infoframe_audio.channel_count, expected.channel_count);
1487 	igt_debug("sampling_freq: got %d, expected %d\n",
1488 		  infoframe_audio.sampling_freq, expected.sampling_freq);
1489 	igt_debug("sample_size: got %d, expected %d\n",
1490 		  infoframe_audio.sample_size, expected.sample_size);
1491 
1492 	if (infoframe_audio.coding_type != INFOFRAME_AUDIO_CT_UNSPECIFIED)
1493 		igt_assert(infoframe_audio.coding_type == expected.coding_type);
1494 	if (infoframe_audio.channel_count >= 0)
1495 		igt_assert(infoframe_audio.channel_count == expected.channel_count);
1496 	if (infoframe_audio.sampling_freq >= 0)
1497 		igt_assert(infoframe_audio.sampling_freq == expected.sampling_freq);
1498 	if (infoframe_audio.sample_size >= 0)
1499 		igt_assert(infoframe_audio.sample_size == expected.sample_size);
1500 }
1501 
1502 static int
audio_output_frequencies_callback(void * data,void * buffer,int samples)1503 audio_output_frequencies_callback(void *data, void *buffer, int samples)
1504 {
1505 	struct audio_state *state = data;
1506 	double *tmp;
1507 	size_t len;
1508 
1509 	len = samples * state->playback.channels;
1510 	tmp = malloc(len * sizeof(double));
1511 	audio_signal_fill(state->signal, tmp, samples);
1512 	audio_convert_to(buffer, tmp, len, state->playback.format);
1513 	free(tmp);
1514 
1515 	return state->run ? 0 : -1;
1516 }
1517 
test_audio_frequencies(struct audio_state * state)1518 static bool test_audio_frequencies(struct audio_state *state)
1519 {
1520 	int freq, step;
1521 	int32_t *recv, *buf;
1522 	double *channel;
1523 	size_t i, j, streak;
1524 	size_t recv_len, buf_len, buf_cap, channel_len;
1525 	bool success;
1526 	int capture_chan;
1527 
1528 	state->signal = audio_signal_init(state->playback.channels,
1529 					  state->playback.rate);
1530 	igt_assert_f(state->signal, "Failed to initialize audio signal\n");
1531 
1532 	/* We'll choose different frequencies per channel to make sure they are
1533 	 * independent from each other. To do so, we'll add a different offset
1534 	 * to the base frequencies for each channel. We need to choose a big
1535 	 * enough offset so that we're sure to detect mixed up channels. We
1536 	 * choose an offset of two 2 bins in the final FFT to enforce a clear
1537 	 * difference.
1538 	 *
1539 	 * Note that we assume capture_rate == playback_rate. We'll assert this
1540 	 * later on. We cannot retrieve the capture rate before starting
1541 	 * playing audio, so we don't really have the choice.
1542 	 */
1543 	step = 2 * state->playback.rate / CAPTURE_SAMPLES;
1544 	for (i = 0; i < test_frequencies_count; i++) {
1545 		for (j = 0; j < state->playback.channels; j++) {
1546 			freq = test_frequencies[i] + j * step;
1547 			audio_signal_add_frequency(state->signal, freq, j);
1548 		}
1549 	}
1550 	audio_signal_synthesize(state->signal);
1551 
1552 	alsa_register_output_callback(state->alsa,
1553 				      audio_output_frequencies_callback, state,
1554 				      PLAYBACK_SAMPLES);
1555 
1556 	audio_state_start(state, "frequencies");
1557 
1558 	igt_assert_f(state->capture.rate == state->playback.rate,
1559 		     "Capture rate (%dHz) doesn't match playback rate (%dHz)\n",
1560 		     state->capture.rate, state->playback.rate);
1561 
1562 	/* Needs to be a multiple of 128, because that's the number of samples
1563 	 * we get per channel each time we receive an audio page from the
1564 	 * Chamelium device.
1565 	 *
1566 	 * Additionally, this value needs to be high enough to guarantee we
1567 	 * capture a full period of each sine we generate. If we capture 2048
1568 	 * samples at a 192KHz sampling rate, we get a full period for a >94Hz
1569 	 * sines. For lower sampling rates, the capture duration will be
1570 	 * longer.
1571 	 */
1572 	channel_len = CAPTURE_SAMPLES;
1573 	channel = malloc(sizeof(double) * channel_len);
1574 
1575 	buf_cap = state->capture.channels * channel_len;
1576 	buf = malloc(sizeof(int32_t) * buf_cap);
1577 	buf_len = 0;
1578 
1579 	recv = NULL;
1580 	recv_len = 0;
1581 
1582 	success = false;
1583 	streak = 0;
1584 	while (!success && state->msec < AUDIO_TIMEOUT) {
1585 		audio_state_receive(state, &recv, &recv_len);
1586 
1587 		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
1588 		buf_len += recv_len;
1589 
1590 		if (buf_len < buf_cap)
1591 			continue;
1592 		igt_assert(buf_len == buf_cap);
1593 
1594 		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
1595 
1596 		for (j = 0; j < state->playback.channels; j++) {
1597 			capture_chan = state->channel_mapping[j];
1598 			igt_assert(capture_chan >= 0);
1599 			igt_debug("Processing channel %zu (captured as "
1600 				  "channel %d)\n", j, capture_chan);
1601 
1602 			audio_extract_channel_s32_le(channel, channel_len,
1603 						     buf, buf_len,
1604 						     state->capture.channels,
1605 						     capture_chan);
1606 
1607 			if (audio_signal_detect(state->signal,
1608 						state->capture.rate, j,
1609 						channel, channel_len))
1610 				streak++;
1611 			else
1612 				streak = 0;
1613 		}
1614 
1615 		buf_len = 0;
1616 
1617 		success = streak == MIN_STREAK * state->playback.channels;
1618 	}
1619 
1620 	audio_state_stop(state, success);
1621 
1622 	free(recv);
1623 	free(buf);
1624 	free(channel);
1625 	audio_signal_fini(state->signal);
1626 
1627 	check_audio_infoframe(state);
1628 
1629 	return success;
1630 }
1631 
audio_output_flatline_callback(void * data,void * buffer,int samples)1632 static int audio_output_flatline_callback(void *data, void *buffer,
1633 					     int samples)
1634 {
1635 	struct audio_state *state = data;
1636 	double *tmp;
1637 	size_t len, i;
1638 
1639 	len = samples * state->playback.channels;
1640 	tmp = malloc(len * sizeof(double));
1641 	for (i = 0; i < len; i++)
1642 		tmp[i] = (state->positive ? 1 : -1) * FLATLINE_AMPLITUDE;
1643 	audio_convert_to(buffer, tmp, len, state->playback.format);
1644 	free(tmp);
1645 
1646 	return state->run ? 0 : -1;
1647 }
1648 
detect_flatline_amplitude(double * buf,size_t buf_len,bool pos)1649 static bool detect_flatline_amplitude(double *buf, size_t buf_len, bool pos)
1650 {
1651 	double expected, min, max;
1652 	size_t i;
1653 	bool ok;
1654 
1655 	min = max = NAN;
1656 	for (i = 0; i < buf_len; i++) {
1657 		if (isnan(min) || buf[i] < min)
1658 			min = buf[i];
1659 		if (isnan(max) || buf[i] > max)
1660 			max = buf[i];
1661 	}
1662 
1663 	expected = (pos ? 1 : -1) * FLATLINE_AMPLITUDE;
1664 	ok = (min >= expected - FLATLINE_AMPLITUDE_ACCURACY &&
1665 	      max <= expected + FLATLINE_AMPLITUDE_ACCURACY);
1666 	if (ok)
1667 		igt_debug("Flatline wave amplitude detected\n");
1668 	else
1669 		igt_debug("Flatline amplitude not detected (min=%f, max=%f)\n",
1670 			  min, max);
1671 	return ok;
1672 }
1673 
detect_falling_edge(double * buf,size_t buf_len)1674 static ssize_t detect_falling_edge(double *buf, size_t buf_len)
1675 {
1676 	size_t i;
1677 
1678 	for (i = 0; i < buf_len; i++) {
1679 		if (buf[i] < 0)
1680 			return i;
1681 	}
1682 
1683 	return -1;
1684 }
1685 
1686 /** test_audio_flatline:
1687  *
1688  * Send a constant value (one positive, then a negative one) and check that:
1689  *
1690  * - The amplitude of the flatline is correct
1691  * - All channels switch from a positive signal to a negative one at the same
1692  *   time (ie. all channels are aligned)
1693  */
test_audio_flatline(struct audio_state * state)1694 static bool test_audio_flatline(struct audio_state *state)
1695 {
1696 	bool success, amp_success, align_success;
1697 	int32_t *recv;
1698 	size_t recv_len, i, channel_len;
1699 	ssize_t j;
1700 	int streak, capture_chan;
1701 	double *channel;
1702 	int falling_edges[CHAMELIUM_MAX_AUDIO_CHANNELS];
1703 
1704 	alsa_register_output_callback(state->alsa,
1705 				      audio_output_flatline_callback, state,
1706 				      PLAYBACK_SAMPLES);
1707 
1708 	/* Start by sending a positive signal */
1709 	state->positive = true;
1710 
1711 	audio_state_start(state, "flatline");
1712 
1713 	for (i = 0; i < state->playback.channels; i++)
1714 		falling_edges[i] = -1;
1715 
1716 	recv = NULL;
1717 	recv_len = 0;
1718 	amp_success = false;
1719 	streak = 0;
1720 	while (!amp_success && state->msec < AUDIO_TIMEOUT) {
1721 		audio_state_receive(state, &recv, &recv_len);
1722 
1723 		igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
1724 
1725 		for (i = 0; i < state->playback.channels; i++) {
1726 			capture_chan = state->channel_mapping[i];
1727 			igt_assert(capture_chan >= 0);
1728 			igt_debug("Processing channel %zu (captured as "
1729 				  "channel %d)\n", i, capture_chan);
1730 
1731 			channel_len = audio_extract_channel_s32_le(NULL, 0,
1732 								   recv, recv_len,
1733 								   state->capture.channels,
1734 								   capture_chan);
1735 			channel = malloc(channel_len * sizeof(double));
1736 			audio_extract_channel_s32_le(channel, channel_len,
1737 						     recv, recv_len,
1738 						     state->capture.channels,
1739 						     capture_chan);
1740 
1741 			/* Check whether the amplitude is fine */
1742 			if (detect_flatline_amplitude(channel, channel_len,
1743 						      state->positive))
1744 				streak++;
1745 			else
1746 				streak = 0;
1747 
1748 			/* If we're now sending a negative signal, detect the
1749 			 * falling edge */
1750 			j = detect_falling_edge(channel, channel_len);
1751 			if (!state->positive && j >= 0) {
1752 				falling_edges[i] = recv_len * state->recv_pages
1753 						   + j;
1754 			}
1755 
1756 			free(channel);
1757 		}
1758 
1759 		amp_success = streak == MIN_STREAK * state->playback.channels;
1760 
1761 		if (amp_success && state->positive) {
1762 			/* Switch to a negative signal after we've detected the
1763 			 * positive one. */
1764 			state->positive = false;
1765 			amp_success = false;
1766 			streak = 0;
1767 			igt_debug("Switching to negative square wave\n");
1768 		}
1769 	}
1770 
1771 	/* Check alignment between all channels by comparing the index of the
1772 	 * falling edge. */
1773 	align_success = true;
1774 	for (i = 0; i < state->playback.channels; i++) {
1775 		if (falling_edges[i] < 0) {
1776 			igt_debug("Falling edge not detected for channel %zu\n",
1777 				  i);
1778 			align_success = false;
1779 			continue;
1780 		}
1781 
1782 		if (abs(falling_edges[0] - falling_edges[i]) >
1783 		    FLATLINE_ALIGN_ACCURACY) {
1784 			igt_debug("Channel alignment mismatch: "
1785 				  "channel 0 has a falling edge at index %d "
1786 				  "while channel %zu has index %d\n",
1787 				  falling_edges[0], i, falling_edges[i]);
1788 			align_success = false;
1789 		}
1790 	}
1791 
1792 	success = amp_success && align_success;
1793 	audio_state_stop(state, success);
1794 
1795 	free(recv);
1796 
1797 	return success;
1798 }
1799 
check_audio_configuration(struct alsa * alsa,snd_pcm_format_t format,int channels,int sampling_rate)1800 static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
1801 				      int channels, int sampling_rate)
1802 {
1803 	if (!alsa_test_output_configuration(alsa, format, channels,
1804 					    sampling_rate)) {
1805 		igt_debug("Skipping test with format %s, sampling rate %d Hz "
1806 			  "and %d channels because at least one of the "
1807 			  "selected output devices doesn't support this "
1808 			  "configuration\n",
1809 			  snd_pcm_format_name(format),
1810 			  sampling_rate, channels);
1811 		return false;
1812 	}
1813 	/* TODO: the Chamelium device sends a malformed signal for some audio
1814 	 * configurations. See crbug.com/950917 */
1815 	if ((format != SND_PCM_FORMAT_S16_LE && sampling_rate >= 44100) ||
1816 			channels > 2) {
1817 		igt_debug("Skipping test with format %s, sampling rate %d Hz "
1818 			  "and %d channels because the Chamelium device "
1819 			  "doesn't support this configuration\n",
1820 			  snd_pcm_format_name(format),
1821 			  sampling_rate, channels);
1822 		return false;
1823 	}
1824 	return true;
1825 }
1826 
1827 static void
test_display_audio(data_t * data,struct chamelium_port * port,const char * audio_device,enum test_edid edid)1828 test_display_audio(data_t *data, struct chamelium_port *port,
1829 		   const char *audio_device, enum test_edid edid)
1830 {
1831 	bool run, success;
1832 	struct alsa *alsa;
1833 	int ret;
1834 	igt_output_t *output;
1835 	igt_plane_t *primary;
1836 	struct igt_fb fb;
1837 	drmModeModeInfo *mode;
1838 	drmModeConnector *connector;
1839 	int fb_id, i, j;
1840 	int channels, sampling_rate;
1841 	snd_pcm_format_t format;
1842 	struct audio_state state;
1843 
1844 	igt_require(alsa_has_exclusive_access());
1845 
1846 	/* Old Chamelium devices need an update for DisplayPort audio and
1847 	 * chamelium_get_audio_format support. */
1848 	igt_require(chamelium_has_audio_support(data->chamelium, port));
1849 
1850 	alsa = alsa_init();
1851 	igt_assert(alsa);
1852 
1853 	reset_state(data, port);
1854 
1855 	output = prepare_output(data, port, edid);
1856 	connector = chamelium_port_get_connector(data->chamelium, port, false);
1857 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
1858 	igt_assert(primary);
1859 
1860 	/* Enable the output because the receiver won't try to receive audio if
1861 	 * it doesn't receive video. */
1862 	igt_assert(connector->count_modes > 0);
1863 	mode = &connector->modes[0];
1864 
1865 	fb_id = igt_create_color_pattern_fb(data->drm_fd,
1866 					    mode->hdisplay, mode->vdisplay,
1867 					    DRM_FORMAT_XRGB8888,
1868 					    LOCAL_DRM_FORMAT_MOD_NONE,
1869 					    0, 0, 0, &fb);
1870 	igt_assert(fb_id > 0);
1871 
1872 	enable_output(data, port, output, mode, &fb);
1873 
1874 	run = false;
1875 	success = true;
1876 	for (i = 0; i < test_sampling_rates_count; i++) {
1877 		for (j = 0; j < test_formats_count; j++) {
1878 			ret = alsa_open_output(alsa, audio_device);
1879 			igt_assert_f(ret >= 0, "Failed to open ALSA output\n");
1880 
1881 			/* TODO: playback on all 8 available channels (this
1882 			 * isn't supported by Chamelium devices yet, see
1883 			 * https://crbug.com/950917) */
1884 			format = test_formats[j];
1885 			channels = PLAYBACK_CHANNELS;
1886 			sampling_rate = test_sampling_rates[i];
1887 
1888 			if (!check_audio_configuration(alsa, format, channels,
1889 						       sampling_rate))
1890 				continue;
1891 
1892 			run = true;
1893 
1894 			audio_state_init(&state, data, alsa, port,
1895 					 format, channels, sampling_rate);
1896 			success &= test_audio_frequencies(&state);
1897 			success &= test_audio_flatline(&state);
1898 			audio_state_fini(&state);
1899 
1900 			alsa_close_output(alsa);
1901 		}
1902 	}
1903 
1904 	/* Make sure we tested at least one frequency and format. */
1905 	igt_assert(run);
1906 	/* Make sure all runs were successful. */
1907 	igt_assert(success);
1908 
1909 	igt_remove_fb(data->drm_fd, &fb);
1910 
1911 	drmModeFreeConnector(connector);
1912 
1913 	free(alsa);
1914 }
1915 
1916 static void
test_display_audio_edid(data_t * data,struct chamelium_port * port,enum test_edid edid)1917 test_display_audio_edid(data_t *data, struct chamelium_port *port,
1918 			enum test_edid edid)
1919 {
1920 	igt_output_t *output;
1921 	igt_plane_t *primary;
1922 	struct igt_fb fb;
1923 	drmModeModeInfo *mode;
1924 	drmModeConnector *connector;
1925 	int fb_id;
1926 	struct eld_entry eld;
1927 	struct eld_sad *sad;
1928 
1929 	reset_state(data, port);
1930 
1931 	output = prepare_output(data, port, edid);
1932 	connector = chamelium_port_get_connector(data->chamelium, port, false);
1933 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
1934 	igt_assert(primary);
1935 
1936 	/* Enable the output because audio cannot be played on inactive
1937 	 * connectors. */
1938 	igt_assert(connector->count_modes > 0);
1939 	mode = &connector->modes[0];
1940 
1941 	fb_id = igt_create_color_pattern_fb(data->drm_fd,
1942 					    mode->hdisplay, mode->vdisplay,
1943 					    DRM_FORMAT_XRGB8888,
1944 					    LOCAL_DRM_FORMAT_MOD_NONE,
1945 					    0, 0, 0, &fb);
1946 	igt_assert(fb_id > 0);
1947 
1948 	enable_output(data, port, output, mode, &fb);
1949 
1950 	igt_assert(eld_get_igt(&eld));
1951 	igt_assert(eld.sads_len == 1);
1952 
1953 	sad = &eld.sads[0];
1954 	igt_assert(sad->coding_type == CEA_SAD_FORMAT_PCM);
1955 	igt_assert(sad->channels == 2);
1956 	igt_assert(sad->rates == (CEA_SAD_SAMPLING_RATE_32KHZ |
1957 		   CEA_SAD_SAMPLING_RATE_44KHZ | CEA_SAD_SAMPLING_RATE_48KHZ));
1958 	igt_assert(sad->bits == (CEA_SAD_SAMPLE_SIZE_16 |
1959 		   CEA_SAD_SAMPLE_SIZE_20 | CEA_SAD_SAMPLE_SIZE_24));
1960 
1961 	igt_remove_fb(data->drm_fd, &fb);
1962 
1963 	drmModeFreeConnector(connector);
1964 }
1965 
randomize_plane_stride(data_t * data,uint32_t width,uint32_t height,uint32_t format,uint64_t modifier,size_t * stride)1966 static void randomize_plane_stride(data_t *data,
1967 				   uint32_t width, uint32_t height,
1968 				   uint32_t format, uint64_t modifier,
1969 				   size_t *stride)
1970 {
1971 	size_t stride_min;
1972 	uint32_t max_tile_w = 4, tile_w, tile_h;
1973 	int i;
1974 	struct igt_fb dummy;
1975 
1976 	stride_min = width * igt_format_plane_bpp(format, 0) / 8;
1977 
1978 	/* Randomize the stride to less than twice the minimum. */
1979 	*stride = (rand() % stride_min) + stride_min;
1980 
1981 	/*
1982 	 * Create a dummy FB to determine bpp for each plane, and calculate
1983 	 * the maximum tile width from that.
1984 	 */
1985 	igt_create_fb(data->drm_fd, 64, 64, format, modifier, &dummy);
1986 	for (i = 0; i < dummy.num_planes; i++) {
1987 		igt_get_fb_tile_size(data->drm_fd, modifier, dummy.plane_bpp[i], &tile_w, &tile_h);
1988 
1989 		if (tile_w > max_tile_w)
1990 			max_tile_w = tile_w;
1991 	}
1992 	igt_remove_fb(data->drm_fd, &dummy);
1993 
1994 	/*
1995 	 * Pixman requires the stride to be aligned to 32-bits, which is
1996 	 * reflected in the initial value of max_tile_w and the hw
1997 	 * may require a multiple of tile width, choose biggest of the 2.
1998 	 */
1999 	*stride = ALIGN(*stride, max_tile_w);
2000 }
2001 
update_tiled_modifier(igt_plane_t * plane,uint32_t width,uint32_t height,uint32_t format,uint64_t * modifier)2002 static void update_tiled_modifier(igt_plane_t *plane, uint32_t width,
2003 				  uint32_t height, uint32_t format,
2004 				  uint64_t *modifier)
2005 {
2006 	if (*modifier == DRM_FORMAT_MOD_BROADCOM_SAND256) {
2007 		/* Randomize the column height to less than twice the minimum. */
2008 		size_t column_height = (rand() % height) + height;
2009 
2010 		igt_debug("Selecting VC4 SAND256 tiling with column height %ld\n",
2011 			  column_height);
2012 
2013 		*modifier = DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(column_height);
2014 	}
2015 }
2016 
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)2017 static void randomize_plane_setup(data_t *data, igt_plane_t *plane,
2018 				  drmModeModeInfo *mode,
2019 				  uint32_t *width, uint32_t *height,
2020 				  uint32_t *format, uint64_t *modifier,
2021 				  bool allow_yuv)
2022 {
2023 	int min_dim;
2024 	uint32_t idx[plane->format_mod_count];
2025 	unsigned int count = 0;
2026 	unsigned int i;
2027 
2028 	/* First pass to count the supported formats. */
2029 	for (i = 0; i < plane->format_mod_count; i++)
2030 		if (igt_fb_supported_format(plane->formats[i]) &&
2031 		    (allow_yuv || !igt_format_is_yuv(plane->formats[i])))
2032 			idx[count++] = i;
2033 
2034 	igt_assert(count > 0);
2035 
2036 	i = idx[rand() % count];
2037 	*format = plane->formats[i];
2038 	*modifier = plane->modifiers[i];
2039 
2040 	update_tiled_modifier(plane, *width, *height, *format, modifier);
2041 
2042 	/*
2043 	 * Randomize width and height in the mode dimensions range.
2044 	 *
2045 	 * Restrict to a min of 2 * min_dim, this way src_w/h are always at
2046 	 * least min_dim, because src_w = width - (rand % w / 2).
2047 	 *
2048 	 * Use a minimum dimension of 16 for YUV, because planar YUV
2049 	 * subsamples the UV plane.
2050 	 */
2051 	min_dim = igt_format_is_yuv(*format) ? 16 : 8;
2052 
2053 	*width = max((rand() % mode->hdisplay) + 1, 2 * min_dim);
2054 	*height = max((rand() % mode->vdisplay) + 1, 2 * min_dim);
2055 }
2056 
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)2057 static void configure_plane(igt_plane_t *plane, uint32_t src_w, uint32_t src_h,
2058 			    uint32_t src_x, uint32_t src_y, uint32_t crtc_w,
2059 			    uint32_t crtc_h, int32_t crtc_x, int32_t crtc_y,
2060 			    struct igt_fb *fb)
2061 {
2062 	igt_plane_set_fb(plane, fb);
2063 
2064 	igt_plane_set_position(plane, crtc_x, crtc_y);
2065 	igt_plane_set_size(plane, crtc_w, crtc_h);
2066 
2067 	igt_fb_set_position(fb, plane, src_x, src_y);
2068 	igt_fb_set_size(fb, plane, src_w, src_h);
2069 }
2070 
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)2071 static void randomize_plane_coordinates(data_t *data, igt_plane_t *plane,
2072 					drmModeModeInfo *mode,
2073 					struct igt_fb *fb,
2074 					uint32_t *src_w, uint32_t *src_h,
2075 					uint32_t *src_x, uint32_t *src_y,
2076 					uint32_t *crtc_w, uint32_t *crtc_h,
2077 					int32_t *crtc_x, int32_t *crtc_y,
2078 					bool allow_scaling)
2079 {
2080 	bool is_yuv = igt_format_is_yuv(fb->drm_format);
2081 	uint32_t width = fb->width, height = fb->height;
2082 	double ratio;
2083 	int ret;
2084 
2085 	/* Randomize source offset in the first half of the original size. */
2086 	*src_x = rand() % (width / 2);
2087 	*src_y = rand() % (height / 2);
2088 
2089 	/* The source size only includes the active source area. */
2090 	*src_w = width - *src_x;
2091 	*src_h = height - *src_y;
2092 
2093 	if (allow_scaling) {
2094 		*crtc_w = (rand() % mode->hdisplay) + 1;
2095 		*crtc_h = (rand() % mode->vdisplay) + 1;
2096 
2097 		/*
2098 		 * Don't bother with scaling if dimensions are quite close in
2099 		 * order to get non-scaling cases more frequently. Also limit
2100 		 * scaling to 3x to avoid agressive filtering that makes
2101 		 * comparison less reliable, and don't go above 2x downsampling
2102 		 * to avoid possible hw limitations.
2103 		 */
2104 
2105 		ratio = ((double) *crtc_w / *src_w);
2106 		if (ratio < 0.5)
2107 			*src_w = *crtc_w * 2;
2108 		else if (ratio > 0.8 && ratio < 1.2)
2109 			*crtc_w = *src_w;
2110 		else if (ratio > 3.0)
2111 			*crtc_w = *src_w * 3;
2112 
2113 		ratio = ((double) *crtc_h / *src_h);
2114 		if (ratio < 0.5)
2115 			*src_h = *crtc_h * 2;
2116 		else if (ratio > 0.8 && ratio < 1.2)
2117 			*crtc_h = *src_h;
2118 		else if (ratio > 3.0)
2119 			*crtc_h = *src_h * 3;
2120 	} else {
2121 		*crtc_w = *src_w;
2122 		*crtc_h = *src_h;
2123 	}
2124 
2125 	if (*crtc_w != *src_w || *crtc_h != *src_h) {
2126 		/*
2127 		 * When scaling is involved, make sure to not go off-bounds or
2128 		 * scaled clipping may result in decimal dimensions, that most
2129 		 * drivers don't support.
2130 		 */
2131 		if (*crtc_w < mode->hdisplay)
2132 			*crtc_x = rand() % (mode->hdisplay - *crtc_w);
2133 		else
2134 			*crtc_x = 0;
2135 
2136 		if (*crtc_h < mode->vdisplay)
2137 			*crtc_y = rand() % (mode->vdisplay - *crtc_h);
2138 		else
2139 			*crtc_y = 0;
2140 	} else {
2141 		/*
2142 		 * Randomize the on-crtc position and allow the plane to go
2143 		 * off-display by less than half of its on-crtc dimensions.
2144 		 */
2145 		*crtc_x = (rand() % mode->hdisplay) - *crtc_w / 2;
2146 		*crtc_y = (rand() % mode->vdisplay) - *crtc_h / 2;
2147 	}
2148 
2149 	configure_plane(plane, *src_w, *src_h, *src_x, *src_y,
2150 			*crtc_w, *crtc_h, *crtc_x, *crtc_y, fb);
2151 	ret = igt_display_try_commit_atomic(&data->display,
2152 					    DRM_MODE_ATOMIC_TEST_ONLY |
2153 					    DRM_MODE_ATOMIC_ALLOW_MODESET,
2154 					    NULL);
2155 	if (!ret)
2156 		return;
2157 
2158 	/* Coordinates are logged in the dumped debug log, so only report w/h on failure here. */
2159 	igt_assert_f(ret != -ENOSPC,"Failure in testcase, invalid coordinates on a %ux%u fb\n", width, height);
2160 
2161 	/* Make YUV coordinates a multiple of 2 and retry the math. */
2162 	if (is_yuv) {
2163 		*src_x &= ~1;
2164 		*src_y &= ~1;
2165 		*src_w &= ~1;
2166 		*src_h &= ~1;
2167 		/* To handle 1:1 scaling, clear crtc_w/h too. */
2168 		*crtc_w &= ~1;
2169 		*crtc_h &= ~1;
2170 
2171 		if (*crtc_x < 0 && (*crtc_x & 1))
2172 			(*crtc_x)++;
2173 		else
2174 			*crtc_x &= ~1;
2175 
2176 		/* If negative, round up to 0 instead of down */
2177 		if (*crtc_y < 0 && (*crtc_y & 1))
2178 			(*crtc_y)++;
2179 		else
2180 			*crtc_y &= ~1;
2181 
2182 		configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
2183 				*crtc_h, *crtc_x, *crtc_y, fb);
2184 		ret = igt_display_try_commit_atomic(&data->display,
2185 						DRM_MODE_ATOMIC_TEST_ONLY |
2186 						DRM_MODE_ATOMIC_ALLOW_MODESET,
2187 						NULL);
2188 		if (!ret)
2189 			return;
2190 	}
2191 
2192 	igt_assert(!ret || allow_scaling);
2193 	igt_info("Scaling ratio %g / %g failed, trying without scaling.\n",
2194 		  ((double) *crtc_w / *src_w), ((double) *crtc_h / *src_h));
2195 
2196 	*crtc_w = *src_w;
2197 	*crtc_h = *src_h;
2198 
2199 	configure_plane(plane, *src_w, *src_h, *src_x, *src_y, *crtc_w,
2200 			*crtc_h, *crtc_x, *crtc_y, fb);
2201 	igt_display_commit_atomic(&data->display,
2202 				  DRM_MODE_ATOMIC_TEST_ONLY |
2203 				  DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
2204 }
2205 
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)2206 static void blit_plane_cairo(data_t *data, cairo_surface_t *result,
2207 			     uint32_t src_w, uint32_t src_h,
2208 			     uint32_t src_x, uint32_t src_y,
2209 			     uint32_t crtc_w, uint32_t crtc_h,
2210 			     int32_t crtc_x, int32_t crtc_y,
2211 			     struct igt_fb *fb)
2212 {
2213 	cairo_surface_t *surface;
2214 	cairo_surface_t *clipped_surface;
2215 	cairo_t *cr;
2216 
2217 	surface = igt_get_cairo_surface(data->drm_fd, fb);
2218 
2219 	if (src_x || src_y) {
2220 		clipped_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
2221 							     src_w, src_h);
2222 
2223 		cr = cairo_create(clipped_surface);
2224 
2225 		cairo_translate(cr, -1. * src_x, -1. * src_y);
2226 
2227 		cairo_set_source_surface(cr, surface, 0, 0);
2228 
2229 		cairo_paint(cr);
2230 		cairo_surface_flush(clipped_surface);
2231 
2232 		cairo_destroy(cr);
2233 	} else {
2234 		clipped_surface = surface;
2235 	}
2236 
2237 	cr = cairo_create(result);
2238 
2239 	cairo_translate(cr, crtc_x, crtc_y);
2240 
2241 	if (src_w != crtc_w || src_h != crtc_h) {
2242 		cairo_scale(cr, (double) crtc_w / src_w,
2243 			    (double) crtc_h / src_h);
2244 	}
2245 
2246 	cairo_set_source_surface(cr, clipped_surface, 0, 0);
2247 	cairo_surface_destroy(clipped_surface);
2248 
2249 	if (src_w != crtc_w || src_h != crtc_h) {
2250 		cairo_pattern_set_filter(cairo_get_source(cr),
2251 					 CAIRO_FILTER_BILINEAR);
2252 		cairo_pattern_set_extend(cairo_get_source(cr),
2253 					 CAIRO_EXTEND_NONE);
2254 	}
2255 
2256 	cairo_paint(cr);
2257 	cairo_surface_flush(result);
2258 
2259 	cairo_destroy(cr);
2260 }
2261 
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)2262 static void prepare_randomized_plane(data_t *data,
2263 				     drmModeModeInfo *mode,
2264 				     igt_plane_t *plane,
2265 				     struct igt_fb *overlay_fb,
2266 				     unsigned int index,
2267 				     cairo_surface_t *result_surface,
2268 				     bool allow_scaling, bool allow_yuv)
2269 {
2270 	struct igt_fb pattern_fb;
2271 	uint32_t overlay_fb_w, overlay_fb_h;
2272 	uint32_t overlay_src_w, overlay_src_h;
2273 	uint32_t overlay_src_x, overlay_src_y;
2274 	int32_t overlay_crtc_x, overlay_crtc_y;
2275 	uint32_t overlay_crtc_w, overlay_crtc_h;
2276 	uint32_t format;
2277 	uint64_t modifier;
2278 	size_t stride;
2279 	bool tiled;
2280 	int fb_id;
2281 
2282 	randomize_plane_setup(data, plane, mode, &overlay_fb_w, &overlay_fb_h,
2283 			      &format, &modifier, allow_yuv);
2284 
2285 	tiled = (modifier != LOCAL_DRM_FORMAT_MOD_NONE);
2286 	igt_debug("Plane %d: framebuffer size %dx%d %s format (%s)\n",
2287 		  index, overlay_fb_w, overlay_fb_h,
2288 		  igt_format_str(format), tiled ? "tiled" : "linear");
2289 
2290 	/* Get a pattern framebuffer for the overlay plane. */
2291 	fb_id = chamelium_get_pattern_fb(data, overlay_fb_w, overlay_fb_h,
2292 					 DRM_FORMAT_XRGB8888, 32, &pattern_fb);
2293 	igt_assert(fb_id > 0);
2294 
2295 	randomize_plane_stride(data, overlay_fb_w, overlay_fb_h,
2296 			       format, modifier, &stride);
2297 
2298 	igt_debug("Plane %d: stride %ld\n", index, stride);
2299 
2300 	fb_id = igt_fb_convert_with_stride(overlay_fb, &pattern_fb, format,
2301 					   modifier, stride);
2302 	igt_assert(fb_id > 0);
2303 
2304 	randomize_plane_coordinates(data, plane, mode, overlay_fb,
2305 				    &overlay_src_w, &overlay_src_h,
2306 				    &overlay_src_x, &overlay_src_y,
2307 				    &overlay_crtc_w, &overlay_crtc_h,
2308 				    &overlay_crtc_x, &overlay_crtc_y,
2309 				    allow_scaling);
2310 
2311 	igt_debug("Plane %d: in-framebuffer size %dx%d\n", index,
2312 		  overlay_src_w, overlay_src_h);
2313 	igt_debug("Plane %d: in-framebuffer position %dx%d\n", index,
2314 		  overlay_src_x, overlay_src_y);
2315 	igt_debug("Plane %d: on-crtc size %dx%d\n", index,
2316 		  overlay_crtc_w, overlay_crtc_h);
2317 	igt_debug("Plane %d: on-crtc position %dx%d\n", index,
2318 		  overlay_crtc_x, overlay_crtc_y);
2319 
2320 	blit_plane_cairo(data, result_surface, overlay_src_w, overlay_src_h,
2321 			 overlay_src_x, overlay_src_y,
2322 			 overlay_crtc_w, overlay_crtc_h,
2323 			 overlay_crtc_x, overlay_crtc_y, &pattern_fb);
2324 
2325 	/* Remove the original pattern framebuffer. */
2326 	igt_remove_fb(data->drm_fd, &pattern_fb);
2327 }
2328 
test_display_planes_random(data_t * data,struct chamelium_port * port,enum chamelium_check check)2329 static void test_display_planes_random(data_t *data,
2330 				       struct chamelium_port *port,
2331 				       enum chamelium_check check)
2332 {
2333 	igt_output_t *output;
2334 	drmModeModeInfo *mode;
2335 	igt_plane_t *primary_plane;
2336 	struct igt_fb primary_fb;
2337 	struct igt_fb result_fb;
2338 	struct igt_fb *overlay_fbs;
2339 	igt_crc_t *crc;
2340 	igt_crc_t *expected_crc;
2341 	struct chamelium_fb_crc_async_data *fb_crc;
2342 	unsigned int overlay_planes_max = 0;
2343 	unsigned int overlay_planes_count;
2344 	cairo_surface_t *result_surface;
2345 	int captured_frame_count;
2346 	bool allow_scaling;
2347 	bool allow_yuv;
2348 	unsigned int i;
2349 	unsigned int fb_id;
2350 
2351 	switch (check) {
2352 	case CHAMELIUM_CHECK_CRC:
2353 		allow_scaling = false;
2354 		allow_yuv = false;
2355 		break;
2356 	case CHAMELIUM_CHECK_CHECKERBOARD:
2357 		allow_scaling = true;
2358 		allow_yuv = true;
2359 		break;
2360 	default:
2361 		igt_assert(false);
2362 	}
2363 
2364 	srand(time(NULL));
2365 
2366 	reset_state(data, port);
2367 
2368 	/* Find the connector and pipe. */
2369 	output = prepare_output(data, port, TEST_EDID_BASE);
2370 
2371 	mode = igt_output_get_mode(output);
2372 
2373 	/* Get a framebuffer for the primary plane. */
2374 	primary_plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
2375 	igt_assert(primary_plane);
2376 
2377 	fb_id = chamelium_get_pattern_fb(data, mode->hdisplay, mode->vdisplay,
2378 					 DRM_FORMAT_XRGB8888, 64, &primary_fb);
2379 	igt_assert(fb_id > 0);
2380 
2381 	/* Get a framebuffer for the cairo composition result. */
2382 	fb_id = igt_create_fb(data->drm_fd, mode->hdisplay,
2383 			      mode->vdisplay, DRM_FORMAT_XRGB8888,
2384 			      LOCAL_DRM_FORMAT_MOD_NONE, &result_fb);
2385 	igt_assert(fb_id > 0);
2386 
2387 	result_surface = igt_get_cairo_surface(data->drm_fd, &result_fb);
2388 
2389 	/* Paint the primary framebuffer on the result surface. */
2390 	blit_plane_cairo(data, result_surface, 0, 0, 0, 0, 0, 0, 0, 0,
2391 			 &primary_fb);
2392 
2393 	/* Configure the primary plane. */
2394 	igt_plane_set_fb(primary_plane, &primary_fb);
2395 
2396 	overlay_planes_max =
2397 		igt_output_count_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
2398 
2399 	/* Limit the number of planes to a reasonable scene. */
2400 	overlay_planes_max = min(overlay_planes_max, 4);
2401 
2402 	overlay_planes_count = (rand() % overlay_planes_max) + 1;
2403 	igt_debug("Using %d overlay planes\n", overlay_planes_count);
2404 
2405 	overlay_fbs = calloc(sizeof(struct igt_fb), overlay_planes_count);
2406 
2407 	for (i = 0; i < overlay_planes_count; i++) {
2408 		struct igt_fb *overlay_fb = &overlay_fbs[i];
2409 		igt_plane_t *plane =
2410 			igt_output_get_plane_type_index(output,
2411 							DRM_PLANE_TYPE_OVERLAY,
2412 							i);
2413 		igt_assert(plane);
2414 
2415 		prepare_randomized_plane(data, mode, plane, overlay_fb, i,
2416 					 result_surface, allow_scaling,
2417 					 allow_yuv);
2418 	}
2419 
2420 	cairo_surface_destroy(result_surface);
2421 
2422 	if (check == CHAMELIUM_CHECK_CRC)
2423 		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
2424 								&result_fb);
2425 
2426 	igt_display_commit2(&data->display, COMMIT_ATOMIC);
2427 
2428 	if (check == CHAMELIUM_CHECK_CRC) {
2429 		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
2430 		crc = chamelium_read_captured_crcs(data->chamelium,
2431 						   &captured_frame_count);
2432 
2433 		igt_assert(captured_frame_count == 1);
2434 
2435 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
2436 
2437 		chamelium_assert_crc_eq_or_dump(data->chamelium,
2438 						expected_crc, crc,
2439 						&result_fb, 0);
2440 
2441 		free(expected_crc);
2442 		free(crc);
2443 	} else if (check == CHAMELIUM_CHECK_CHECKERBOARD) {
2444 		struct chamelium_frame_dump *dump;
2445 
2446 		dump = chamelium_port_dump_pixels(data->chamelium, port, 0, 0,
2447 						  0, 0);
2448 		chamelium_assert_frame_match_or_dump(data->chamelium, port,
2449 						     dump, &result_fb, check);
2450 		chamelium_destroy_frame_dump(dump);
2451 	}
2452 
2453 	for (i = 0; i < overlay_planes_count; i++)
2454 		igt_remove_fb(data->drm_fd, &overlay_fbs[i]);
2455 
2456 	free(overlay_fbs);
2457 
2458 	igt_remove_fb(data->drm_fd, &primary_fb);
2459 	igt_remove_fb(data->drm_fd, &result_fb);
2460 }
2461 
2462 static void
test_hpd_without_ddc(data_t * data,struct chamelium_port * port)2463 test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
2464 {
2465 	struct udev_monitor *mon = igt_watch_hotplug();
2466 
2467 	reset_state(data, port);
2468 	igt_flush_hotplugs(mon);
2469 
2470 	/* Disable the DDC on the connector and make sure we still get a
2471 	 * hotplug
2472 	 */
2473 	chamelium_port_set_ddc_state(data->chamelium, port, false);
2474 	chamelium_plug(data->chamelium, port);
2475 
2476 	igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
2477 	igt_assert_eq(reprobe_connector(data, port), DRM_MODE_CONNECTED);
2478 
2479 	igt_cleanup_hotplug(mon);
2480 }
2481 
2482 static void
test_hpd_storm_detect(data_t * data,struct chamelium_port * port,int width)2483 test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
2484 {
2485 	struct udev_monitor *mon;
2486 	int count = 0;
2487 
2488 	igt_require_hpd_storm_ctl(data->drm_fd);
2489 	reset_state(data, port);
2490 
2491 	igt_hpd_storm_set_threshold(data->drm_fd, 1);
2492 	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
2493 	igt_assert(igt_hpd_storm_detected(data->drm_fd));
2494 
2495 	mon = igt_watch_hotplug();
2496 	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
2497 
2498 	/*
2499 	 * Polling should have been enabled by the HPD storm at this point,
2500 	 * so we should only get at most 1 hotplug event
2501 	 */
2502 	igt_until_timeout(5)
2503 		count += igt_hotplug_detected(mon, 1);
2504 	igt_assert_lt(count, 2);
2505 
2506 	igt_cleanup_hotplug(mon);
2507 	igt_hpd_storm_reset(data->drm_fd);
2508 }
2509 
2510 static void
test_hpd_storm_disable(data_t * data,struct chamelium_port * port,int width)2511 test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
2512 {
2513 	igt_require_hpd_storm_ctl(data->drm_fd);
2514 	reset_state(data, port);
2515 
2516 	igt_hpd_storm_set_threshold(data->drm_fd, 0);
2517 	chamelium_fire_hpd_pulses(data->chamelium, port,
2518 				  width, 10);
2519 	igt_assert(!igt_hpd_storm_detected(data->drm_fd));
2520 
2521 	igt_hpd_storm_reset(data->drm_fd);
2522 }
2523 
get_edid(enum test_edid edid)2524 static const struct edid *get_edid(enum test_edid edid)
2525 {
2526 	switch (edid) {
2527 	case TEST_EDID_BASE:
2528 		return igt_kms_get_base_edid();
2529 	case TEST_EDID_ALT:
2530 		return igt_kms_get_alt_edid();
2531 	case TEST_EDID_HDMI_AUDIO:
2532 		return igt_kms_get_hdmi_audio_edid();
2533 	case TEST_EDID_DP_AUDIO:
2534 		return igt_kms_get_dp_audio_edid();
2535 	case TEST_EDID_ASPECT_RATIO:
2536 		return get_aspect_ratio_edid();
2537 	}
2538 	assert(0); /* unreachable */
2539 }
2540 
2541 #define for_each_port(p, port)            \
2542 	for (p = 0, port = data.ports[p]; \
2543 	     p < data.port_count;         \
2544 	     p++, port = data.ports[p])
2545 
2546 #define connector_subtest(name__, type__)                    \
2547 	igt_subtest(name__)                                  \
2548 		for_each_port(p, port)                       \
2549 			if (chamelium_port_get_type(port) == \
2550 			    DRM_MODE_CONNECTOR_ ## type__)
2551 
2552 static data_t data;
2553 
2554 igt_main
2555 {
2556 	struct chamelium_port *port;
2557 	int p;
2558 	size_t i;
2559 
2560 	igt_fixture {
2561 		igt_skip_on_simulation();
2562 
2563 		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
2564 		data.chamelium = chamelium_init(data.drm_fd);
2565 		igt_require(data.chamelium);
2566 
2567 		data.ports = chamelium_get_ports(data.chamelium,
2568 						 &data.port_count);
2569 
2570 		for (i = 0; i < TEST_EDID_COUNT; ++i) {
2571 			data.edids[i] = chamelium_new_edid(data.chamelium,
2572 							   get_edid(i));
2573 		}
2574 
2575 		/* So fbcon doesn't try to reprobe things itself */
2576 		kmstest_set_vt_graphics_mode();
2577 
2578 		igt_display_require(&data.display, data.drm_fd);
2579 		igt_require(data.display.is_atomic);
2580 	}
2581 
2582 	igt_subtest_group {
2583 		igt_fixture {
2584 			require_connector_present(
2585 			    &data, DRM_MODE_CONNECTOR_DisplayPort);
2586 		}
2587 
2588 		connector_subtest("dp-hpd", DisplayPort)
2589 			test_basic_hotplug(&data, port,
2590 					   HPD_TOGGLE_COUNT_DP_HDMI);
2591 
2592 		connector_subtest("dp-hpd-fast", DisplayPort)
2593 			test_basic_hotplug(&data, port,
2594 					   HPD_TOGGLE_COUNT_FAST);
2595 
2596 		connector_subtest("dp-edid-read", DisplayPort) {
2597 			test_edid_read(&data, port, TEST_EDID_BASE);
2598 			test_edid_read(&data, port, TEST_EDID_ALT);
2599 		}
2600 
2601 		connector_subtest("dp-hpd-after-suspend", DisplayPort)
2602 			test_suspend_resume_hpd(&data, port,
2603 						SUSPEND_STATE_MEM,
2604 						SUSPEND_TEST_NONE);
2605 
2606 		connector_subtest("dp-hpd-after-hibernate", DisplayPort)
2607 			test_suspend_resume_hpd(&data, port,
2608 						SUSPEND_STATE_DISK,
2609 						SUSPEND_TEST_DEVICES);
2610 
2611 		connector_subtest("dp-hpd-storm", DisplayPort)
2612 			test_hpd_storm_detect(&data, port,
2613 					      HPD_STORM_PULSE_INTERVAL_DP);
2614 
2615 		connector_subtest("dp-hpd-storm-disable", DisplayPort)
2616 			test_hpd_storm_disable(&data, port,
2617 					       HPD_STORM_PULSE_INTERVAL_DP);
2618 
2619 		connector_subtest("dp-link-status", DisplayPort)
2620 			test_link_status(&data, port);
2621 
2622 		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
2623 			test_suspend_resume_edid_change(&data, port,
2624 							SUSPEND_STATE_MEM,
2625 							SUSPEND_TEST_NONE,
2626 							TEST_EDID_BASE,
2627 							TEST_EDID_ALT);
2628 
2629 		connector_subtest("dp-edid-change-during-hibernate", DisplayPort)
2630 			test_suspend_resume_edid_change(&data, port,
2631 							SUSPEND_STATE_DISK,
2632 							SUSPEND_TEST_DEVICES,
2633 							TEST_EDID_BASE,
2634 							TEST_EDID_ALT);
2635 
2636 		connector_subtest("dp-crc-single", DisplayPort)
2637 			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
2638 					       CHAMELIUM_CHECK_CRC, 1);
2639 
2640 		connector_subtest("dp-crc-fast", DisplayPort)
2641 			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
2642 					      CHAMELIUM_CHECK_CRC, 1);
2643 
2644 		connector_subtest("dp-crc-multiple", DisplayPort)
2645 			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
2646 					       CHAMELIUM_CHECK_CRC, 3);
2647 
2648 		connector_subtest("dp-frame-dump", DisplayPort)
2649 			test_display_frame_dump(&data, port);
2650 
2651 		connector_subtest("dp-mode-timings", DisplayPort)
2652 			test_mode_timings(&data, port);
2653 
2654 		connector_subtest("dp-audio", DisplayPort)
2655 			test_display_audio(&data, port, "HDMI",
2656 					   TEST_EDID_DP_AUDIO);
2657 
2658 		connector_subtest("dp-audio-edid", DisplayPort)
2659 			test_display_audio_edid(&data, port,
2660 						TEST_EDID_DP_AUDIO);
2661 	}
2662 
2663 	igt_subtest_group {
2664 		igt_fixture {
2665 			require_connector_present(
2666 			    &data, DRM_MODE_CONNECTOR_HDMIA);
2667 		}
2668 
2669 		connector_subtest("hdmi-hpd", HDMIA)
2670 			test_basic_hotplug(&data, port,
2671 					   HPD_TOGGLE_COUNT_DP_HDMI);
2672 
2673 		connector_subtest("hdmi-hpd-fast", HDMIA)
2674 			test_basic_hotplug(&data, port,
2675 					   HPD_TOGGLE_COUNT_FAST);
2676 
2677 		connector_subtest("hdmi-edid-read", HDMIA) {
2678 			test_edid_read(&data, port, TEST_EDID_BASE);
2679 			test_edid_read(&data, port, TEST_EDID_ALT);
2680 		}
2681 
2682 		connector_subtest("hdmi-hpd-after-suspend", HDMIA)
2683 			test_suspend_resume_hpd(&data, port,
2684 						SUSPEND_STATE_MEM,
2685 						SUSPEND_TEST_NONE);
2686 
2687 		connector_subtest("hdmi-hpd-after-hibernate", HDMIA)
2688 			test_suspend_resume_hpd(&data, port,
2689 						SUSPEND_STATE_DISK,
2690 						SUSPEND_TEST_DEVICES);
2691 
2692 		connector_subtest("hdmi-hpd-storm", HDMIA)
2693 			test_hpd_storm_detect(&data, port,
2694 					      HPD_STORM_PULSE_INTERVAL_HDMI);
2695 
2696 		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
2697 			test_hpd_storm_disable(&data, port,
2698 					       HPD_STORM_PULSE_INTERVAL_HDMI);
2699 
2700 		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
2701 			test_suspend_resume_edid_change(&data, port,
2702 							SUSPEND_STATE_MEM,
2703 							SUSPEND_TEST_NONE,
2704 							TEST_EDID_BASE,
2705 							TEST_EDID_ALT);
2706 
2707 		connector_subtest("hdmi-edid-change-during-hibernate", HDMIA)
2708 			test_suspend_resume_edid_change(&data, port,
2709 							SUSPEND_STATE_DISK,
2710 							SUSPEND_TEST_DEVICES,
2711 							TEST_EDID_BASE,
2712 							TEST_EDID_ALT);
2713 
2714 		connector_subtest("hdmi-crc-single", HDMIA)
2715 			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
2716 					       CHAMELIUM_CHECK_CRC, 1);
2717 
2718 		connector_subtest("hdmi-crc-fast", HDMIA)
2719 			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
2720 					      CHAMELIUM_CHECK_CRC, 1);
2721 
2722 		connector_subtest("hdmi-crc-multiple", HDMIA)
2723 			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
2724 					       CHAMELIUM_CHECK_CRC, 3);
2725 
2726 		connector_subtest("hdmi-crc-argb8888", HDMIA)
2727 			test_display_one_mode(&data, port, DRM_FORMAT_ARGB8888,
2728 					      CHAMELIUM_CHECK_CRC, 1);
2729 
2730 		connector_subtest("hdmi-crc-abgr8888", HDMIA)
2731 			test_display_one_mode(&data, port, DRM_FORMAT_ABGR8888,
2732 					      CHAMELIUM_CHECK_CRC, 1);
2733 
2734 		connector_subtest("hdmi-crc-xrgb8888", HDMIA)
2735 			test_display_one_mode(&data, port, DRM_FORMAT_XRGB8888,
2736 					      CHAMELIUM_CHECK_CRC, 1);
2737 
2738 		connector_subtest("hdmi-crc-xbgr8888", HDMIA)
2739 			test_display_one_mode(&data, port, DRM_FORMAT_XBGR8888,
2740 					      CHAMELIUM_CHECK_CRC, 1);
2741 
2742 		connector_subtest("hdmi-crc-rgb888", HDMIA)
2743 			test_display_one_mode(&data, port, DRM_FORMAT_RGB888,
2744 					      CHAMELIUM_CHECK_CRC, 1);
2745 
2746 		connector_subtest("hdmi-crc-bgr888", HDMIA)
2747 			test_display_one_mode(&data, port, DRM_FORMAT_BGR888,
2748 					      CHAMELIUM_CHECK_CRC, 1);
2749 
2750 		connector_subtest("hdmi-crc-rgb565", HDMIA)
2751 			test_display_one_mode(&data, port, DRM_FORMAT_RGB565,
2752 					      CHAMELIUM_CHECK_CRC, 1);
2753 
2754 		connector_subtest("hdmi-crc-bgr565", HDMIA)
2755 			test_display_one_mode(&data, port, DRM_FORMAT_BGR565,
2756 					      CHAMELIUM_CHECK_CRC, 1);
2757 
2758 		connector_subtest("hdmi-crc-argb1555", HDMIA)
2759 			test_display_one_mode(&data, port, DRM_FORMAT_ARGB1555,
2760 					      CHAMELIUM_CHECK_CRC, 1);
2761 
2762 		connector_subtest("hdmi-crc-xrgb1555", HDMIA)
2763 			test_display_one_mode(&data, port, DRM_FORMAT_XRGB1555,
2764 					      CHAMELIUM_CHECK_CRC, 1);
2765 
2766 		connector_subtest("hdmi-crc-planes-random", HDMIA)
2767 			test_display_planes_random(&data, port,
2768 						   CHAMELIUM_CHECK_CRC);
2769 
2770 		connector_subtest("hdmi-cmp-nv12", HDMIA)
2771 			test_display_one_mode(&data, port, DRM_FORMAT_NV12,
2772 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2773 
2774 		connector_subtest("hdmi-cmp-nv16", HDMIA)
2775 			test_display_one_mode(&data, port, DRM_FORMAT_NV16,
2776 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2777 
2778 		connector_subtest("hdmi-cmp-nv21", HDMIA)
2779 			test_display_one_mode(&data, port, DRM_FORMAT_NV21,
2780 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2781 
2782 		connector_subtest("hdmi-cmp-nv61", HDMIA)
2783 			test_display_one_mode(&data, port, DRM_FORMAT_NV61,
2784 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2785 
2786 		connector_subtest("hdmi-cmp-yu12", HDMIA)
2787 			test_display_one_mode(&data, port, DRM_FORMAT_YUV420,
2788 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2789 
2790 		connector_subtest("hdmi-cmp-yu16", HDMIA)
2791 			test_display_one_mode(&data, port, DRM_FORMAT_YUV422,
2792 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2793 
2794 		connector_subtest("hdmi-cmp-yv12", HDMIA)
2795 			test_display_one_mode(&data, port, DRM_FORMAT_YVU420,
2796 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2797 
2798 		connector_subtest("hdmi-cmp-yv16", HDMIA)
2799 			test_display_one_mode(&data, port, DRM_FORMAT_YVU422,
2800 					      CHAMELIUM_CHECK_CHECKERBOARD, 1);
2801 
2802 		connector_subtest("hdmi-cmp-planes-random", HDMIA)
2803 			test_display_planes_random(&data, port,
2804 						   CHAMELIUM_CHECK_CHECKERBOARD);
2805 
2806 		connector_subtest("hdmi-frame-dump", HDMIA)
2807 			test_display_frame_dump(&data, port);
2808 
2809 		connector_subtest("hdmi-mode-timings", HDMIA)
2810 			test_mode_timings(&data, port);
2811 
2812 		connector_subtest("hdmi-audio", HDMIA)
2813 			test_display_audio(&data, port, "HDMI",
2814 					   TEST_EDID_HDMI_AUDIO);
2815 
2816 		connector_subtest("hdmi-audio-edid", HDMIA)
2817 			test_display_audio_edid(&data, port,
2818 						TEST_EDID_HDMI_AUDIO);
2819 
2820 		connector_subtest("hdmi-aspect-ratio", HDMIA)
2821 			test_display_aspect_ratio(&data, port);
2822 	}
2823 
2824 	igt_subtest_group {
2825 		igt_fixture {
2826 			require_connector_present(
2827 			    &data, DRM_MODE_CONNECTOR_VGA);
2828 		}
2829 
2830 		connector_subtest("vga-hpd", VGA)
2831 			test_basic_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA);
2832 
2833 		connector_subtest("vga-hpd-fast", VGA)
2834 			test_basic_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST);
2835 
2836 		connector_subtest("vga-edid-read", VGA) {
2837 			test_edid_read(&data, port, TEST_EDID_BASE);
2838 			test_edid_read(&data, port, TEST_EDID_ALT);
2839 		}
2840 
2841 		connector_subtest("vga-hpd-after-suspend", VGA)
2842 			test_suspend_resume_hpd(&data, port,
2843 						SUSPEND_STATE_MEM,
2844 						SUSPEND_TEST_NONE);
2845 
2846 		connector_subtest("vga-hpd-after-hibernate", VGA)
2847 			test_suspend_resume_hpd(&data, port,
2848 						SUSPEND_STATE_DISK,
2849 						SUSPEND_TEST_DEVICES);
2850 
2851 		connector_subtest("vga-hpd-without-ddc", VGA)
2852 			test_hpd_without_ddc(&data, port);
2853 
2854 		connector_subtest("vga-frame-dump", VGA)
2855 			test_display_all_modes(&data, port, DRM_FORMAT_XRGB8888,
2856 					       CHAMELIUM_CHECK_ANALOG, 1);
2857 	}
2858 
2859 	igt_subtest_group {
2860 		igt_subtest("common-hpd-after-suspend")
2861 			test_suspend_resume_hpd_common(&data,
2862 						       SUSPEND_STATE_MEM,
2863 						       SUSPEND_TEST_NONE);
2864 
2865 		igt_subtest("common-hpd-after-hibernate")
2866 			test_suspend_resume_hpd_common(&data,
2867 						       SUSPEND_STATE_DISK,
2868 						       SUSPEND_TEST_DEVICES);
2869 	}
2870 
2871 	igt_fixture {
2872 		igt_display_fini(&data.display);
2873 		close(data.drm_fd);
2874 	}
2875 }
2876