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