xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_setmode.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
3*d83cc019SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
4*d83cc019SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
5*d83cc019SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6*d83cc019SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
7*d83cc019SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
8*d83cc019SAndroid Build Coastguard Worker  *
9*d83cc019SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
10*d83cc019SAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
11*d83cc019SAndroid Build Coastguard Worker  *
12*d83cc019SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13*d83cc019SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14*d83cc019SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15*d83cc019SAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16*d83cc019SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17*d83cc019SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18*d83cc019SAndroid Build Coastguard Worker  * IN THE SOFTWARE.
19*d83cc019SAndroid Build Coastguard Worker  *
20*d83cc019SAndroid Build Coastguard Worker  * Authors:
21*d83cc019SAndroid Build Coastguard Worker  *    Imre Deak <[email protected]>
22*d83cc019SAndroid Build Coastguard Worker  */
23*d83cc019SAndroid Build Coastguard Worker #include "config.h"
24*d83cc019SAndroid Build Coastguard Worker 
25*d83cc019SAndroid Build Coastguard Worker #include "igt.h"
26*d83cc019SAndroid Build Coastguard Worker #if defined(USE_CAIRO_PIXMAN)
27*d83cc019SAndroid Build Coastguard Worker #include <cairo.h>
28*d83cc019SAndroid Build Coastguard Worker #endif
29*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
30*d83cc019SAndroid Build Coastguard Worker #include <stdint.h>
31*d83cc019SAndroid Build Coastguard Worker #include <unistd.h>
32*d83cc019SAndroid Build Coastguard Worker #include <string.h>
33*d83cc019SAndroid Build Coastguard Worker #include <sys/time.h>
34*d83cc019SAndroid Build Coastguard Worker #include <math.h>
35*d83cc019SAndroid Build Coastguard Worker #include "intel_bufmgr.h"
36*d83cc019SAndroid Build Coastguard Worker 
37*d83cc019SAndroid Build Coastguard Worker #define MAX_CONNECTORS  10
38*d83cc019SAndroid Build Coastguard Worker #define MAX_CRTCS       6
39*d83cc019SAndroid Build Coastguard Worker 
40*d83cc019SAndroid Build Coastguard Worker /* max combinations with repetitions */
41*d83cc019SAndroid Build Coastguard Worker #define MAX_COMBINATION_ELEMS   MAX_CRTCS
42*d83cc019SAndroid Build Coastguard Worker 
43*d83cc019SAndroid Build Coastguard Worker static int drm_fd;
44*d83cc019SAndroid Build Coastguard Worker static drmModeRes *drm_resources;
45*d83cc019SAndroid Build Coastguard Worker static int filter_test_id;
46*d83cc019SAndroid Build Coastguard Worker static bool dry_run;
47*d83cc019SAndroid Build Coastguard Worker 
48*d83cc019SAndroid Build Coastguard Worker const drmModeModeInfo mode_640_480 = {
49*d83cc019SAndroid Build Coastguard Worker 	.name		= "640x480",
50*d83cc019SAndroid Build Coastguard Worker 	.vrefresh	= 60,
51*d83cc019SAndroid Build Coastguard Worker 	.clock		= 25200,
52*d83cc019SAndroid Build Coastguard Worker 
53*d83cc019SAndroid Build Coastguard Worker 	.hdisplay	= 640,
54*d83cc019SAndroid Build Coastguard Worker 	.hsync_start	= 656,
55*d83cc019SAndroid Build Coastguard Worker 	.hsync_end	= 752,
56*d83cc019SAndroid Build Coastguard Worker 	.htotal		= 800,
57*d83cc019SAndroid Build Coastguard Worker 
58*d83cc019SAndroid Build Coastguard Worker 	.vdisplay	= 480,
59*d83cc019SAndroid Build Coastguard Worker 	.vsync_start	= 490,
60*d83cc019SAndroid Build Coastguard Worker 	.vsync_end	= 492,
61*d83cc019SAndroid Build Coastguard Worker 	.vtotal		= 525,
62*d83cc019SAndroid Build Coastguard Worker 
63*d83cc019SAndroid Build Coastguard Worker 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
64*d83cc019SAndroid Build Coastguard Worker };
65*d83cc019SAndroid Build Coastguard Worker 
66*d83cc019SAndroid Build Coastguard Worker enum test_flags {
67*d83cc019SAndroid Build Coastguard Worker 	TEST_INVALID			= 0x01,
68*d83cc019SAndroid Build Coastguard Worker 	TEST_CLONE			= 0x02,
69*d83cc019SAndroid Build Coastguard Worker 	TEST_SINGLE_CRTC_CLONE		= 0x04,
70*d83cc019SAndroid Build Coastguard Worker 	TEST_EXCLUSIVE_CRTC_CLONE	= 0x08,
71*d83cc019SAndroid Build Coastguard Worker 	TEST_STEALING			= 0x10,
72*d83cc019SAndroid Build Coastguard Worker 	TEST_TIMINGS			= 0x20,
73*d83cc019SAndroid Build Coastguard Worker };
74*d83cc019SAndroid Build Coastguard Worker 
75*d83cc019SAndroid Build Coastguard Worker struct test_config {
76*d83cc019SAndroid Build Coastguard Worker 	const char *name;
77*d83cc019SAndroid Build Coastguard Worker 	enum test_flags flags;
78*d83cc019SAndroid Build Coastguard Worker 	drmModeRes *resources;
79*d83cc019SAndroid Build Coastguard Worker };
80*d83cc019SAndroid Build Coastguard Worker 
81*d83cc019SAndroid Build Coastguard Worker struct connector_config {
82*d83cc019SAndroid Build Coastguard Worker 	drmModeConnector *connector;
83*d83cc019SAndroid Build Coastguard Worker 	int crtc_idx;
84*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfo default_mode;
85*d83cc019SAndroid Build Coastguard Worker };
86*d83cc019SAndroid Build Coastguard Worker 
87*d83cc019SAndroid Build Coastguard Worker struct crtc_config {
88*d83cc019SAndroid Build Coastguard Worker 	int crtc_idx;
89*d83cc019SAndroid Build Coastguard Worker 	int crtc_id;
90*d83cc019SAndroid Build Coastguard Worker 	int pipe_id;
91*d83cc019SAndroid Build Coastguard Worker 	int connector_count;
92*d83cc019SAndroid Build Coastguard Worker 	struct connector_config *cconfs;
93*d83cc019SAndroid Build Coastguard Worker 	struct igt_fb fb_info;
94*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfo mode;
95*d83cc019SAndroid Build Coastguard Worker };
96*d83cc019SAndroid Build Coastguard Worker 
drm_mode_equal(drmModeModeInfo * m1,drmModeModeInfo * m2)97*d83cc019SAndroid Build Coastguard Worker static bool drm_mode_equal(drmModeModeInfo *m1, drmModeModeInfo *m2)
98*d83cc019SAndroid Build Coastguard Worker {
99*d83cc019SAndroid Build Coastguard Worker #define COMP(x) do { if (m1->x != m2->x) return false; } while (0)
100*d83cc019SAndroid Build Coastguard Worker 	COMP(vrefresh);
101*d83cc019SAndroid Build Coastguard Worker 	COMP(clock);
102*d83cc019SAndroid Build Coastguard Worker 	COMP(hdisplay);
103*d83cc019SAndroid Build Coastguard Worker 	COMP(hsync_start);
104*d83cc019SAndroid Build Coastguard Worker 	COMP(hsync_end);
105*d83cc019SAndroid Build Coastguard Worker 	COMP(htotal);
106*d83cc019SAndroid Build Coastguard Worker 	COMP(vdisplay);
107*d83cc019SAndroid Build Coastguard Worker 	COMP(vsync_start);
108*d83cc019SAndroid Build Coastguard Worker 	COMP(vsync_end);
109*d83cc019SAndroid Build Coastguard Worker 	COMP(vtotal);
110*d83cc019SAndroid Build Coastguard Worker 	COMP(flags);
111*d83cc019SAndroid Build Coastguard Worker 
112*d83cc019SAndroid Build Coastguard Worker 	return true;
113*d83cc019SAndroid Build Coastguard Worker }
114*d83cc019SAndroid Build Coastguard Worker 
connector_supports_mode(drmModeConnector * connector,drmModeModeInfo * mode)115*d83cc019SAndroid Build Coastguard Worker static bool connector_supports_mode(drmModeConnector *connector,
116*d83cc019SAndroid Build Coastguard Worker 				    drmModeModeInfo *mode)
117*d83cc019SAndroid Build Coastguard Worker {
118*d83cc019SAndroid Build Coastguard Worker 	int i;
119*d83cc019SAndroid Build Coastguard Worker 
120*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector->count_modes; i++)
121*d83cc019SAndroid Build Coastguard Worker 		if (drm_mode_equal(&connector->modes[i], mode))
122*d83cc019SAndroid Build Coastguard Worker 			return true;
123*d83cc019SAndroid Build Coastguard Worker 
124*d83cc019SAndroid Build Coastguard Worker 	return false;
125*d83cc019SAndroid Build Coastguard Worker }
126*d83cc019SAndroid Build Coastguard Worker 
crtc_supports_mode(struct crtc_config * crtc,drmModeModeInfo * mode)127*d83cc019SAndroid Build Coastguard Worker static bool crtc_supports_mode(struct crtc_config *crtc, drmModeModeInfo *mode)
128*d83cc019SAndroid Build Coastguard Worker {
129*d83cc019SAndroid Build Coastguard Worker 	int i;
130*d83cc019SAndroid Build Coastguard Worker 
131*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->connector_count; i++) {
132*d83cc019SAndroid Build Coastguard Worker 		if (!connector_supports_mode(crtc->cconfs[i].connector, mode))
133*d83cc019SAndroid Build Coastguard Worker 			return false;
134*d83cc019SAndroid Build Coastguard Worker 	}
135*d83cc019SAndroid Build Coastguard Worker 
136*d83cc019SAndroid Build Coastguard Worker 	return true;
137*d83cc019SAndroid Build Coastguard Worker }
138*d83cc019SAndroid Build Coastguard Worker 
139*d83cc019SAndroid Build Coastguard Worker #if defined(USE_CAIRO_PIXMAN)
paint_fb(struct igt_fb * fb,const char * test_name,const char ** crtc_str,int crtc_count,int current_crtc_idx)140*d83cc019SAndroid Build Coastguard Worker static int paint_fb(struct igt_fb *fb, const char *test_name,
141*d83cc019SAndroid Build Coastguard Worker 		    const char **crtc_str, int crtc_count, int current_crtc_idx)
142*d83cc019SAndroid Build Coastguard Worker {
143*d83cc019SAndroid Build Coastguard Worker 	double x, y;
144*d83cc019SAndroid Build Coastguard Worker 	cairo_t *cr;
145*d83cc019SAndroid Build Coastguard Worker 	int i;
146*d83cc019SAndroid Build Coastguard Worker 
147*d83cc019SAndroid Build Coastguard Worker 	cr = igt_get_cairo_ctx(drm_fd, fb);
148*d83cc019SAndroid Build Coastguard Worker 
149*d83cc019SAndroid Build Coastguard Worker 	cairo_move_to(cr, fb->width / 2, fb->height / 2);
150*d83cc019SAndroid Build Coastguard Worker 	cairo_set_font_size(cr, 24);
151*d83cc019SAndroid Build Coastguard Worker 	igt_cairo_printf_line(cr, align_hcenter, 40, "%s", test_name);
152*d83cc019SAndroid Build Coastguard Worker 
153*d83cc019SAndroid Build Coastguard Worker 	cairo_get_current_point(cr, &x, &y);
154*d83cc019SAndroid Build Coastguard Worker 	cairo_move_to(cr, 60, y);
155*d83cc019SAndroid Build Coastguard Worker 
156*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc_count; i++) {
157*d83cc019SAndroid Build Coastguard Worker 		if (i == current_crtc_idx) {
158*d83cc019SAndroid Build Coastguard Worker 			cairo_get_current_point(cr, &x, &y);
159*d83cc019SAndroid Build Coastguard Worker 			cairo_move_to(cr, x - 20, y);
160*d83cc019SAndroid Build Coastguard Worker 			igt_cairo_printf_line(cr, align_right, 20, "X");
161*d83cc019SAndroid Build Coastguard Worker 			cairo_move_to(cr, x, y);
162*d83cc019SAndroid Build Coastguard Worker 		}
163*d83cc019SAndroid Build Coastguard Worker 		igt_cairo_printf_line(cr, align_left, 20, "%s",
164*d83cc019SAndroid Build Coastguard Worker 					  crtc_str[i]);
165*d83cc019SAndroid Build Coastguard Worker 	}
166*d83cc019SAndroid Build Coastguard Worker 
167*d83cc019SAndroid Build Coastguard Worker 	igt_put_cairo_ctx(drm_fd, fb, cr);
168*d83cc019SAndroid Build Coastguard Worker 
169*d83cc019SAndroid Build Coastguard Worker 	return 0;
170*d83cc019SAndroid Build Coastguard Worker }
171*d83cc019SAndroid Build Coastguard Worker #endif
172*d83cc019SAndroid Build Coastguard Worker 
create_fb_for_crtc(struct crtc_config * crtc,struct igt_fb * fb_info)173*d83cc019SAndroid Build Coastguard Worker static void create_fb_for_crtc(struct crtc_config *crtc,
174*d83cc019SAndroid Build Coastguard Worker 			       struct igt_fb *fb_info)
175*d83cc019SAndroid Build Coastguard Worker {
176*d83cc019SAndroid Build Coastguard Worker 	int bpp;
177*d83cc019SAndroid Build Coastguard Worker 	int depth;
178*d83cc019SAndroid Build Coastguard Worker 	int fb_id;
179*d83cc019SAndroid Build Coastguard Worker 
180*d83cc019SAndroid Build Coastguard Worker 	bpp = 32;
181*d83cc019SAndroid Build Coastguard Worker 	depth = 24;
182*d83cc019SAndroid Build Coastguard Worker 	fb_id = igt_create_pattern_fb(drm_fd, crtc->mode.hdisplay,
183*d83cc019SAndroid Build Coastguard Worker 				      crtc->mode.vdisplay,
184*d83cc019SAndroid Build Coastguard Worker 				      igt_bpp_depth_to_drm_format(bpp, depth),
185*d83cc019SAndroid Build Coastguard Worker 				      LOCAL_DRM_FORMAT_MOD_NONE,
186*d83cc019SAndroid Build Coastguard Worker 				      fb_info);
187*d83cc019SAndroid Build Coastguard Worker 	igt_assert_lt(0, fb_id);
188*d83cc019SAndroid Build Coastguard Worker }
189*d83cc019SAndroid Build Coastguard Worker 
get_mode_for_crtc(struct crtc_config * crtc,drmModeModeInfo * mode_ret)190*d83cc019SAndroid Build Coastguard Worker static void get_mode_for_crtc(struct crtc_config *crtc,
191*d83cc019SAndroid Build Coastguard Worker 			      drmModeModeInfo *mode_ret)
192*d83cc019SAndroid Build Coastguard Worker {
193*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfo *mode;
194*d83cc019SAndroid Build Coastguard Worker 	int i;
195*d83cc019SAndroid Build Coastguard Worker 
196*d83cc019SAndroid Build Coastguard Worker 	/*
197*d83cc019SAndroid Build Coastguard Worker 	 * First try to select a default mode that is supported by all
198*d83cc019SAndroid Build Coastguard Worker 	 * connectors.
199*d83cc019SAndroid Build Coastguard Worker 	 */
200*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->connector_count; i++) {
201*d83cc019SAndroid Build Coastguard Worker 		mode = &crtc->cconfs[i].default_mode;
202*d83cc019SAndroid Build Coastguard Worker 		if (crtc_supports_mode(crtc, mode))
203*d83cc019SAndroid Build Coastguard Worker 			goto found;
204*d83cc019SAndroid Build Coastguard Worker 	}
205*d83cc019SAndroid Build Coastguard Worker 
206*d83cc019SAndroid Build Coastguard Worker 	/*
207*d83cc019SAndroid Build Coastguard Worker 	 * Then just fall back to find any that is supported by all
208*d83cc019SAndroid Build Coastguard Worker 	 * connectors.
209*d83cc019SAndroid Build Coastguard Worker 	 */
210*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->cconfs[0].connector->count_modes; i++) {
211*d83cc019SAndroid Build Coastguard Worker 		mode = &crtc->cconfs[0].connector->modes[i];
212*d83cc019SAndroid Build Coastguard Worker 		if (crtc_supports_mode(crtc, mode))
213*d83cc019SAndroid Build Coastguard Worker 			goto found;
214*d83cc019SAndroid Build Coastguard Worker 	}
215*d83cc019SAndroid Build Coastguard Worker 
216*d83cc019SAndroid Build Coastguard Worker 	/*
217*d83cc019SAndroid Build Coastguard Worker 	 * If none is found then just pick the default mode from all connectors
218*d83cc019SAndroid Build Coastguard Worker 	 * with the smallest clock, hope the other connectors can support it by
219*d83cc019SAndroid Build Coastguard Worker 	 * scaling etc.
220*d83cc019SAndroid Build Coastguard Worker 	 */
221*d83cc019SAndroid Build Coastguard Worker 	mode = &crtc->cconfs[0].default_mode;
222*d83cc019SAndroid Build Coastguard Worker 	for (i = 1; i < crtc->connector_count; i++)
223*d83cc019SAndroid Build Coastguard Worker 		if (crtc->cconfs[i].default_mode.clock < mode->clock)
224*d83cc019SAndroid Build Coastguard Worker 			mode = &crtc->cconfs[i].default_mode;
225*d83cc019SAndroid Build Coastguard Worker found:
226*d83cc019SAndroid Build Coastguard Worker 	*mode_ret = *mode;
227*d83cc019SAndroid Build Coastguard Worker }
228*d83cc019SAndroid Build Coastguard Worker 
get_encoder_idx(drmModeRes * resources,drmModeEncoder * encoder)229*d83cc019SAndroid Build Coastguard Worker static int get_encoder_idx(drmModeRes *resources, drmModeEncoder *encoder)
230*d83cc019SAndroid Build Coastguard Worker {
231*d83cc019SAndroid Build Coastguard Worker 	int i;
232*d83cc019SAndroid Build Coastguard Worker 
233*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < resources->count_encoders; i++)
234*d83cc019SAndroid Build Coastguard Worker 		if (resources->encoders[i] == encoder->encoder_id)
235*d83cc019SAndroid Build Coastguard Worker 			return i;
236*d83cc019SAndroid Build Coastguard Worker 	igt_assert(0);
237*d83cc019SAndroid Build Coastguard Worker }
238*d83cc019SAndroid Build Coastguard Worker 
get_crtc_config_str(struct crtc_config * crtc,char * buf,size_t buf_size)239*d83cc019SAndroid Build Coastguard Worker static void get_crtc_config_str(struct crtc_config *crtc, char *buf,
240*d83cc019SAndroid Build Coastguard Worker 				size_t buf_size)
241*d83cc019SAndroid Build Coastguard Worker {
242*d83cc019SAndroid Build Coastguard Worker 	int pos;
243*d83cc019SAndroid Build Coastguard Worker 	int i;
244*d83cc019SAndroid Build Coastguard Worker 
245*d83cc019SAndroid Build Coastguard Worker 	pos = snprintf(buf, buf_size,
246*d83cc019SAndroid Build Coastguard Worker 		       "CRTC[%d] [Pipe %s] Mode: %s@%dHz Connectors: ",
247*d83cc019SAndroid Build Coastguard Worker 		       crtc->crtc_id, kmstest_pipe_name(crtc->pipe_id),
248*d83cc019SAndroid Build Coastguard Worker 		       crtc->mode.name, crtc->mode.vrefresh);
249*d83cc019SAndroid Build Coastguard Worker 	if (pos > buf_size)
250*d83cc019SAndroid Build Coastguard Worker 		return;
251*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->connector_count; i++) {
252*d83cc019SAndroid Build Coastguard Worker 		drmModeConnector *connector = crtc->cconfs[i].connector;
253*d83cc019SAndroid Build Coastguard Worker 
254*d83cc019SAndroid Build Coastguard Worker 		pos += snprintf(&buf[pos], buf_size - pos,
255*d83cc019SAndroid Build Coastguard Worker 			"%s%s-%d[%d]", i ? ", " : "",
256*d83cc019SAndroid Build Coastguard Worker 			kmstest_connector_type_str(connector->connector_type),
257*d83cc019SAndroid Build Coastguard Worker 			connector->connector_type_id, connector->connector_id);
258*d83cc019SAndroid Build Coastguard Worker 		if (pos > buf_size)
259*d83cc019SAndroid Build Coastguard Worker 			return;
260*d83cc019SAndroid Build Coastguard Worker 	}
261*d83cc019SAndroid Build Coastguard Worker }
262*d83cc019SAndroid Build Coastguard Worker 
setup_crtcs(drmModeRes * resources,struct connector_config * cconf,int connector_count,struct crtc_config * crtcs,int * crtc_count_ret,bool * config_valid_ret)263*d83cc019SAndroid Build Coastguard Worker static void setup_crtcs(drmModeRes *resources, struct connector_config *cconf,
264*d83cc019SAndroid Build Coastguard Worker 			int connector_count, struct crtc_config *crtcs,
265*d83cc019SAndroid Build Coastguard Worker 			int *crtc_count_ret, bool *config_valid_ret)
266*d83cc019SAndroid Build Coastguard Worker {
267*d83cc019SAndroid Build Coastguard Worker 	struct crtc_config *crtc;
268*d83cc019SAndroid Build Coastguard Worker 	int crtc_count;
269*d83cc019SAndroid Build Coastguard Worker 	bool config_valid;
270*d83cc019SAndroid Build Coastguard Worker 	int i;
271*d83cc019SAndroid Build Coastguard Worker 	int encoder_usage_count[resources->count_encoders];
272*d83cc019SAndroid Build Coastguard Worker 
273*d83cc019SAndroid Build Coastguard Worker 	kmstest_unset_all_crtcs(drm_fd, resources);
274*d83cc019SAndroid Build Coastguard Worker 
275*d83cc019SAndroid Build Coastguard Worker 	i = 0;
276*d83cc019SAndroid Build Coastguard Worker 	crtc_count = 0;
277*d83cc019SAndroid Build Coastguard Worker 	crtc = crtcs;
278*d83cc019SAndroid Build Coastguard Worker 	config_valid = true;
279*d83cc019SAndroid Build Coastguard Worker 
280*d83cc019SAndroid Build Coastguard Worker 	while (i < connector_count) {
281*d83cc019SAndroid Build Coastguard Worker 		drmModeCrtc *drm_crtc;
282*d83cc019SAndroid Build Coastguard Worker 		unsigned long encoder_mask;
283*d83cc019SAndroid Build Coastguard Worker 		int j;
284*d83cc019SAndroid Build Coastguard Worker 
285*d83cc019SAndroid Build Coastguard Worker 		igt_assert_lt(crtc_count, MAX_CRTCS);
286*d83cc019SAndroid Build Coastguard Worker 
287*d83cc019SAndroid Build Coastguard Worker 		crtc->crtc_idx = cconf[i].crtc_idx;
288*d83cc019SAndroid Build Coastguard Worker 		drm_crtc = drmModeGetCrtc(drm_fd,
289*d83cc019SAndroid Build Coastguard Worker 					  resources->crtcs[crtc->crtc_idx]);
290*d83cc019SAndroid Build Coastguard Worker 		crtc->crtc_id = drm_crtc->crtc_id;
291*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeCrtc(drm_crtc);
292*d83cc019SAndroid Build Coastguard Worker 		crtc->pipe_id = kmstest_get_pipe_from_crtc_id(drm_fd,
293*d83cc019SAndroid Build Coastguard Worker 							      crtc->crtc_id);
294*d83cc019SAndroid Build Coastguard Worker 
295*d83cc019SAndroid Build Coastguard Worker 		crtc->connector_count = 1;
296*d83cc019SAndroid Build Coastguard Worker 		for (j = i + 1; j < connector_count; j++)
297*d83cc019SAndroid Build Coastguard Worker 			if (cconf[j].crtc_idx == crtc->crtc_idx)
298*d83cc019SAndroid Build Coastguard Worker 				crtc->connector_count++;
299*d83cc019SAndroid Build Coastguard Worker 
300*d83cc019SAndroid Build Coastguard Worker 		crtc->cconfs = malloc(sizeof(*crtc->cconfs) *
301*d83cc019SAndroid Build Coastguard Worker 				      crtc->connector_count);
302*d83cc019SAndroid Build Coastguard Worker 		igt_assert(crtc->cconfs);
303*d83cc019SAndroid Build Coastguard Worker 
304*d83cc019SAndroid Build Coastguard Worker 		encoder_mask = 0;
305*d83cc019SAndroid Build Coastguard Worker 		for (j = 0; j < crtc->connector_count; j++) {
306*d83cc019SAndroid Build Coastguard Worker 			drmModeConnector *connector;
307*d83cc019SAndroid Build Coastguard Worker 			drmModeEncoder *encoder;
308*d83cc019SAndroid Build Coastguard Worker 
309*d83cc019SAndroid Build Coastguard Worker 			crtc->cconfs[j] = cconf[i + j];
310*d83cc019SAndroid Build Coastguard Worker 			connector = cconf[i + j].connector;
311*d83cc019SAndroid Build Coastguard Worker 
312*d83cc019SAndroid Build Coastguard Worker 			/* Intel connectors have only a single encoder */
313*d83cc019SAndroid Build Coastguard Worker 			if (connector->count_encoders == 1) {
314*d83cc019SAndroid Build Coastguard Worker 				encoder = drmModeGetEncoder(drm_fd,
315*d83cc019SAndroid Build Coastguard Worker 							    connector->encoders[0]);
316*d83cc019SAndroid Build Coastguard Worker 			} else {
317*d83cc019SAndroid Build Coastguard Worker 				igt_assert_eq(connector->connector_type,
318*d83cc019SAndroid Build Coastguard Worker 					      DRM_MODE_CONNECTOR_DisplayPort);
319*d83cc019SAndroid Build Coastguard Worker 
320*d83cc019SAndroid Build Coastguard Worker 				igt_assert(connector->count_encoders >= crtc->crtc_idx);
321*d83cc019SAndroid Build Coastguard Worker 				encoder = drmModeGetEncoder(drm_fd,
322*d83cc019SAndroid Build Coastguard Worker 					connector->encoders[crtc_count]);
323*d83cc019SAndroid Build Coastguard Worker 			}
324*d83cc019SAndroid Build Coastguard Worker 			igt_assert(encoder);
325*d83cc019SAndroid Build Coastguard Worker 
326*d83cc019SAndroid Build Coastguard Worker 			config_valid &= !!(encoder->possible_crtcs &
327*d83cc019SAndroid Build Coastguard Worker 					  (1 << crtc->crtc_idx));
328*d83cc019SAndroid Build Coastguard Worker 
329*d83cc019SAndroid Build Coastguard Worker 			encoder_mask |= 1 << get_encoder_idx(resources,
330*d83cc019SAndroid Build Coastguard Worker 							     encoder);
331*d83cc019SAndroid Build Coastguard Worker 			config_valid &= !(encoder_mask &
332*d83cc019SAndroid Build Coastguard Worker 					  ~encoder->possible_clones);
333*d83cc019SAndroid Build Coastguard Worker 
334*d83cc019SAndroid Build Coastguard Worker 			drmModeFreeEncoder(encoder);
335*d83cc019SAndroid Build Coastguard Worker 		}
336*d83cc019SAndroid Build Coastguard Worker 		get_mode_for_crtc(crtc, &crtc->mode);
337*d83cc019SAndroid Build Coastguard Worker 		create_fb_for_crtc(crtc, &crtc->fb_info);
338*d83cc019SAndroid Build Coastguard Worker 
339*d83cc019SAndroid Build Coastguard Worker 		i += crtc->connector_count;
340*d83cc019SAndroid Build Coastguard Worker 		crtc_count++;
341*d83cc019SAndroid Build Coastguard Worker 		crtc++;
342*d83cc019SAndroid Build Coastguard Worker 	}
343*d83cc019SAndroid Build Coastguard Worker 
344*d83cc019SAndroid Build Coastguard Worker 	memset(encoder_usage_count, 0, sizeof(encoder_usage_count));
345*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector_count; i++) {
346*d83cc019SAndroid Build Coastguard Worker 		drmModeConnector *connector = cconf[i].connector;
347*d83cc019SAndroid Build Coastguard Worker 		drmModeEncoder *encoder;
348*d83cc019SAndroid Build Coastguard Worker 		int idx = 0;
349*d83cc019SAndroid Build Coastguard Worker 
350*d83cc019SAndroid Build Coastguard Worker 		/* DP MST configs are presumed valid */
351*d83cc019SAndroid Build Coastguard Worker 		if (connector->count_encoders > 1)
352*d83cc019SAndroid Build Coastguard Worker 			idx = cconf[i].crtc_idx;
353*d83cc019SAndroid Build Coastguard Worker 
354*d83cc019SAndroid Build Coastguard Worker 		encoder = drmModeGetEncoder(drm_fd, connector->encoders[idx]);
355*d83cc019SAndroid Build Coastguard Worker 		encoder_usage_count[get_encoder_idx(resources, encoder)]++;
356*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeEncoder(encoder);
357*d83cc019SAndroid Build Coastguard Worker 	}
358*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < resources->count_encoders; i++)
359*d83cc019SAndroid Build Coastguard Worker 		if (encoder_usage_count[i] > 1)
360*d83cc019SAndroid Build Coastguard Worker 			config_valid = false;
361*d83cc019SAndroid Build Coastguard Worker 
362*d83cc019SAndroid Build Coastguard Worker 	*crtc_count_ret = crtc_count;
363*d83cc019SAndroid Build Coastguard Worker 	*config_valid_ret = config_valid;
364*d83cc019SAndroid Build Coastguard Worker }
365*d83cc019SAndroid Build Coastguard Worker 
cleanup_crtcs(struct crtc_config * crtcs,int crtc_count)366*d83cc019SAndroid Build Coastguard Worker static void cleanup_crtcs(struct crtc_config *crtcs, int crtc_count)
367*d83cc019SAndroid Build Coastguard Worker {
368*d83cc019SAndroid Build Coastguard Worker 	int i;
369*d83cc019SAndroid Build Coastguard Worker 
370*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc_count; i++) {
371*d83cc019SAndroid Build Coastguard Worker 		igt_remove_fb(drm_fd, &crtcs[i].fb_info);
372*d83cc019SAndroid Build Coastguard Worker 		drmModeSetCrtc(drm_fd, crtcs[i].crtc_id, 0, 0, 0, NULL, 0, NULL);
373*d83cc019SAndroid Build Coastguard Worker 
374*d83cc019SAndroid Build Coastguard Worker 		free(crtcs[i].cconfs);
375*d83cc019SAndroid Build Coastguard Worker 	}
376*d83cc019SAndroid Build Coastguard Worker }
377*d83cc019SAndroid Build Coastguard Worker 
get_connector_ids(struct crtc_config * crtc)378*d83cc019SAndroid Build Coastguard Worker static uint32_t *get_connector_ids(struct crtc_config *crtc)
379*d83cc019SAndroid Build Coastguard Worker {
380*d83cc019SAndroid Build Coastguard Worker 	uint32_t *ids;
381*d83cc019SAndroid Build Coastguard Worker 	int i;
382*d83cc019SAndroid Build Coastguard Worker 
383*d83cc019SAndroid Build Coastguard Worker 	ids = malloc(sizeof(*ids) * crtc->connector_count);
384*d83cc019SAndroid Build Coastguard Worker 	igt_assert(ids);
385*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->connector_count; i++)
386*d83cc019SAndroid Build Coastguard Worker 		ids[i] = crtc->cconfs[i].connector->connector_id;
387*d83cc019SAndroid Build Coastguard Worker 
388*d83cc019SAndroid Build Coastguard Worker 	return ids;
389*d83cc019SAndroid Build Coastguard Worker }
390*d83cc019SAndroid Build Coastguard Worker 
test_stealing(int fd,struct crtc_config * crtc,uint32_t * ids)391*d83cc019SAndroid Build Coastguard Worker static int test_stealing(int fd, struct crtc_config *crtc, uint32_t *ids)
392*d83cc019SAndroid Build Coastguard Worker {
393*d83cc019SAndroid Build Coastguard Worker 	int i, ret = 0;
394*d83cc019SAndroid Build Coastguard Worker 
395*d83cc019SAndroid Build Coastguard Worker 	if (!crtc->connector_count)
396*d83cc019SAndroid Build Coastguard Worker 		return drmModeSetCrtc(fd, crtc->crtc_id,
397*d83cc019SAndroid Build Coastguard Worker 				     crtc->fb_info.fb_id, 0, 0,
398*d83cc019SAndroid Build Coastguard Worker 				     ids, crtc->connector_count, &crtc->mode);
399*d83cc019SAndroid Build Coastguard Worker 
400*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc->connector_count; ++i) {
401*d83cc019SAndroid Build Coastguard Worker 		ret = drmModeSetCrtc(fd, crtc->crtc_id,
402*d83cc019SAndroid Build Coastguard Worker 				     crtc->fb_info.fb_id, 0, 0,
403*d83cc019SAndroid Build Coastguard Worker 				     &ids[i], 1, &crtc->mode);
404*d83cc019SAndroid Build Coastguard Worker 
405*d83cc019SAndroid Build Coastguard Worker 		igt_assert_eq(ret, 0);
406*d83cc019SAndroid Build Coastguard Worker 
407*d83cc019SAndroid Build Coastguard Worker 		ret = drmModeSetCrtc(fd, crtc->crtc_id,
408*d83cc019SAndroid Build Coastguard Worker 				     crtc->fb_info.fb_id, 0, 0,
409*d83cc019SAndroid Build Coastguard Worker 				     ids, crtc->connector_count, &crtc->mode);
410*d83cc019SAndroid Build Coastguard Worker 
411*d83cc019SAndroid Build Coastguard Worker 		/* This should fail with -EINVAL */
412*d83cc019SAndroid Build Coastguard Worker 		if (!ret)
413*d83cc019SAndroid Build Coastguard Worker 			return 0;
414*d83cc019SAndroid Build Coastguard Worker 	}
415*d83cc019SAndroid Build Coastguard Worker 
416*d83cc019SAndroid Build Coastguard Worker 	return ret;
417*d83cc019SAndroid Build Coastguard Worker }
418*d83cc019SAndroid Build Coastguard Worker 
frame_time(const drmModeModeInfo * kmode)419*d83cc019SAndroid Build Coastguard Worker static double frame_time(const drmModeModeInfo *kmode)
420*d83cc019SAndroid Build Coastguard Worker {
421*d83cc019SAndroid Build Coastguard Worker 	return 1000.0 * kmode->htotal * kmode->vtotal / kmode->clock;
422*d83cc019SAndroid Build Coastguard Worker }
423*d83cc019SAndroid Build Coastguard Worker 
line_time(const drmModeModeInfo * kmode)424*d83cc019SAndroid Build Coastguard Worker static double line_time(const drmModeModeInfo *kmode)
425*d83cc019SAndroid Build Coastguard Worker {
426*d83cc019SAndroid Build Coastguard Worker 	return 1000.0 * kmode->htotal / kmode->clock;
427*d83cc019SAndroid Build Coastguard Worker }
428*d83cc019SAndroid Build Coastguard Worker 
check_timings(int crtc_idx,const drmModeModeInfo * kmode)429*d83cc019SAndroid Build Coastguard Worker static void check_timings(int crtc_idx, const drmModeModeInfo *kmode)
430*d83cc019SAndroid Build Coastguard Worker {
431*d83cc019SAndroid Build Coastguard Worker #define CALIBRATE_TS_STEPS 120 /* ~2s has to be less than 128! */
432*d83cc019SAndroid Build Coastguard Worker 	drmVBlank wait;
433*d83cc019SAndroid Build Coastguard Worker 	igt_stats_t stats;
434*d83cc019SAndroid Build Coastguard Worker 	uint32_t last_seq;
435*d83cc019SAndroid Build Coastguard Worker 	uint64_t last_timestamp;
436*d83cc019SAndroid Build Coastguard Worker 	double expected;
437*d83cc019SAndroid Build Coastguard Worker 	double accuracy;
438*d83cc019SAndroid Build Coastguard Worker 	double mean;
439*d83cc019SAndroid Build Coastguard Worker 	double stddev;
440*d83cc019SAndroid Build Coastguard Worker 	int n;
441*d83cc019SAndroid Build Coastguard Worker 
442*d83cc019SAndroid Build Coastguard Worker 	memset(&wait, 0, sizeof(wait));
443*d83cc019SAndroid Build Coastguard Worker 	wait.request.type = kmstest_get_vbl_flag(crtc_idx);
444*d83cc019SAndroid Build Coastguard Worker 	wait.request.type |= DRM_VBLANK_RELATIVE | DRM_VBLANK_NEXTONMISS;
445*d83cc019SAndroid Build Coastguard Worker 	do_or_die(drmWaitVBlank(drm_fd, &wait));
446*d83cc019SAndroid Build Coastguard Worker 
447*d83cc019SAndroid Build Coastguard Worker 	last_seq = wait.reply.sequence;
448*d83cc019SAndroid Build Coastguard Worker 	last_timestamp = wait.reply.tval_sec;
449*d83cc019SAndroid Build Coastguard Worker 	last_timestamp *= 1000000;
450*d83cc019SAndroid Build Coastguard Worker 	last_timestamp += wait.reply.tval_usec;
451*d83cc019SAndroid Build Coastguard Worker 
452*d83cc019SAndroid Build Coastguard Worker 	memset(&wait, 0, sizeof(wait));
453*d83cc019SAndroid Build Coastguard Worker 	wait.request.type = kmstest_get_vbl_flag(crtc_idx);
454*d83cc019SAndroid Build Coastguard Worker 	wait.request.type |= DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
455*d83cc019SAndroid Build Coastguard Worker 	wait.request.sequence = last_seq;
456*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < CALIBRATE_TS_STEPS; n++) {
457*d83cc019SAndroid Build Coastguard Worker 		drmVBlank check = {};
458*d83cc019SAndroid Build Coastguard Worker 
459*d83cc019SAndroid Build Coastguard Worker 		++wait.request.sequence;
460*d83cc019SAndroid Build Coastguard Worker 		do_or_die(drmWaitVBlank(drm_fd, &wait));
461*d83cc019SAndroid Build Coastguard Worker 
462*d83cc019SAndroid Build Coastguard Worker 		/* Double check that haven't already missed the vblank */
463*d83cc019SAndroid Build Coastguard Worker 		check.request.type = kmstest_get_vbl_flag(crtc_idx);
464*d83cc019SAndroid Build Coastguard Worker 		check.request.type |= DRM_VBLANK_RELATIVE;
465*d83cc019SAndroid Build Coastguard Worker 		do_or_die(drmWaitVBlank(drm_fd, &check));
466*d83cc019SAndroid Build Coastguard Worker 
467*d83cc019SAndroid Build Coastguard Worker 		igt_assert(!igt_vblank_after(check.reply.sequence, wait.request.sequence));
468*d83cc019SAndroid Build Coastguard Worker 	}
469*d83cc019SAndroid Build Coastguard Worker 
470*d83cc019SAndroid Build Coastguard Worker 	igt_stats_init_with_size(&stats, CALIBRATE_TS_STEPS);
471*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < CALIBRATE_TS_STEPS; n++) {
472*d83cc019SAndroid Build Coastguard Worker 		struct drm_event_vblank ev;
473*d83cc019SAndroid Build Coastguard Worker 		uint64_t now;
474*d83cc019SAndroid Build Coastguard Worker 
475*d83cc019SAndroid Build Coastguard Worker 		igt_assert(read(drm_fd, &ev, sizeof(ev)) == sizeof(ev));
476*d83cc019SAndroid Build Coastguard Worker 		igt_assert_eq(ev.sequence, last_seq + 1);
477*d83cc019SAndroid Build Coastguard Worker 
478*d83cc019SAndroid Build Coastguard Worker 		now = ev.tv_sec;
479*d83cc019SAndroid Build Coastguard Worker 		now *= 1000000;
480*d83cc019SAndroid Build Coastguard Worker 		now += ev.tv_usec;
481*d83cc019SAndroid Build Coastguard Worker 
482*d83cc019SAndroid Build Coastguard Worker 		igt_stats_push(&stats, now - last_timestamp);
483*d83cc019SAndroid Build Coastguard Worker 
484*d83cc019SAndroid Build Coastguard Worker 		last_timestamp = now;
485*d83cc019SAndroid Build Coastguard Worker 		last_seq = ev.sequence;
486*d83cc019SAndroid Build Coastguard Worker 	}
487*d83cc019SAndroid Build Coastguard Worker 
488*d83cc019SAndroid Build Coastguard Worker 	expected = frame_time(kmode);
489*d83cc019SAndroid Build Coastguard Worker 
490*d83cc019SAndroid Build Coastguard Worker 	mean = igt_stats_get_mean(&stats);
491*d83cc019SAndroid Build Coastguard Worker 	stddev = igt_stats_get_std_deviation(&stats);
492*d83cc019SAndroid Build Coastguard Worker 
493*d83cc019SAndroid Build Coastguard Worker 	/* 99.7% samples fall within `accuracy` on both sides of mean in normal
494*d83cc019SAndroid Build Coastguard Worker 	 * distribution if `accuracy = 3 * sigma`.
495*d83cc019SAndroid Build Coastguard Worker 	 * https://en.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7_rule
496*d83cc019SAndroid Build Coastguard Worker 	 *
497*d83cc019SAndroid Build Coastguard Worker 	 * The value of 99.7% was chosen to suit requirements of test cases
498*d83cc019SAndroid Build Coastguard Worker 	 * which depend on timing, giving the lowest acceptable MTBF of 5.6s
499*d83cc019SAndroid Build Coastguard Worker 	 * for 60Hz sampling rate.
500*d83cc019SAndroid Build Coastguard Worker 	 */
501*d83cc019SAndroid Build Coastguard Worker 	accuracy = 3. * stddev;
502*d83cc019SAndroid Build Coastguard Worker 
503*d83cc019SAndroid Build Coastguard Worker 	igt_info("Expected frametime: %.0fus; measured %.1fus +- %.3fus accuracy %.2f%% [%.2f scanlines]\n",
504*d83cc019SAndroid Build Coastguard Worker 		 expected, mean, stddev,
505*d83cc019SAndroid Build Coastguard Worker 		 100 * accuracy / mean, accuracy / line_time(kmode));
506*d83cc019SAndroid Build Coastguard Worker 
507*d83cc019SAndroid Build Coastguard Worker 	/* 99.7% samples within one scanline on each side of mean */
508*d83cc019SAndroid Build Coastguard Worker 	igt_assert_f(accuracy < line_time(kmode),
509*d83cc019SAndroid Build Coastguard Worker 		     "vblank accuracy (%.3fus, %.1f%%) worse than a scanline (%.3fus)\n",
510*d83cc019SAndroid Build Coastguard Worker 		     accuracy, 100 * accuracy / mean, line_time(kmode));
511*d83cc019SAndroid Build Coastguard Worker 
512*d83cc019SAndroid Build Coastguard Worker 	/* At least 90% of frame times fall within the one scanline on each
513*d83cc019SAndroid Build Coastguard Worker 	 * side of expected mean.
514*d83cc019SAndroid Build Coastguard Worker 	 *
515*d83cc019SAndroid Build Coastguard Worker 	 * Expected scanline duration:
516*d83cc019SAndroid Build Coastguard Worker 	 * 	(expected - accuracy, expected + accuracy).
517*d83cc019SAndroid Build Coastguard Worker 	 * Assuming maximum difference allowed:
518*d83cc019SAndroid Build Coastguard Worker 	 * 	expected = mean + n * sigma
519*d83cc019SAndroid Build Coastguard Worker 	 * the scanline duration becomes:
520*d83cc019SAndroid Build Coastguard Worker 	 * 	(mean - accuracy + n * sigma, mean + accuracy + n * sigma)
521*d83cc019SAndroid Build Coastguard Worker 	 * The expected scanline captures the following number of samples
522*d83cc019SAndroid Build Coastguard Worker 	 * from each side of expected:
523*d83cc019SAndroid Build Coastguard Worker 	 * 	(erf(abs(-(accuracy/sigma) + n) / sqrt(2))
524*d83cc019SAndroid Build Coastguard Worker 	 * 	+ erf((accuracy/sigma) + n) / sqrt(2))) / 2
525*d83cc019SAndroid Build Coastguard Worker 	 * 	= samples
526*d83cc019SAndroid Build Coastguard Worker 	 *
527*d83cc019SAndroid Build Coastguard Worker 	 * Solving for samples = 0.9:
528*d83cc019SAndroid Build Coastguard Worker 	 * 	n = 1.718
529*d83cc019SAndroid Build Coastguard Worker 	 *
530*d83cc019SAndroid Build Coastguard Worker 	 * See:
531*d83cc019SAndroid Build Coastguard Worker 	 * https://en.wikipedia.org/wiki/Standard_deviation#Rules_for_normally_distributed_data
532*d83cc019SAndroid Build Coastguard Worker 	 */
533*d83cc019SAndroid Build Coastguard Worker 	igt_assert_f(fabs(mean - expected) < 1.718 * stddev,
534*d83cc019SAndroid Build Coastguard Worker 		     "vblank interval differs from modeline! expected %.1fus, measured %1.fus +- %.3fus, difference %.1fus (%.1f sigma)\n",
535*d83cc019SAndroid Build Coastguard Worker 		     expected, mean, stddev,
536*d83cc019SAndroid Build Coastguard Worker 		     fabs(mean - expected), fabs(mean - expected) / stddev);
537*d83cc019SAndroid Build Coastguard Worker }
538*d83cc019SAndroid Build Coastguard Worker 
test_crtc_config(const struct test_config * tconf,struct crtc_config * crtcs,int crtc_count)539*d83cc019SAndroid Build Coastguard Worker static void test_crtc_config(const struct test_config *tconf,
540*d83cc019SAndroid Build Coastguard Worker 			     struct crtc_config *crtcs, int crtc_count)
541*d83cc019SAndroid Build Coastguard Worker {
542*d83cc019SAndroid Build Coastguard Worker 	char str_buf[MAX_CRTCS][1024];
543*d83cc019SAndroid Build Coastguard Worker 	const char *crtc_strs[MAX_CRTCS];
544*d83cc019SAndroid Build Coastguard Worker 	struct crtc_config *crtc;
545*d83cc019SAndroid Build Coastguard Worker 	static int test_id;
546*d83cc019SAndroid Build Coastguard Worker 	bool config_failed = false;
547*d83cc019SAndroid Build Coastguard Worker 	int ret = 0;
548*d83cc019SAndroid Build Coastguard Worker 	int i;
549*d83cc019SAndroid Build Coastguard Worker 
550*d83cc019SAndroid Build Coastguard Worker 	test_id++;
551*d83cc019SAndroid Build Coastguard Worker 
552*d83cc019SAndroid Build Coastguard Worker 	if (filter_test_id && filter_test_id != test_id)
553*d83cc019SAndroid Build Coastguard Worker 		return;
554*d83cc019SAndroid Build Coastguard Worker 
555*d83cc019SAndroid Build Coastguard Worker 	igt_info("  Test id#%d CRTC count %d\n", test_id, crtc_count);
556*d83cc019SAndroid Build Coastguard Worker 
557*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc_count; i++) {
558*d83cc019SAndroid Build Coastguard Worker 		get_crtc_config_str(&crtcs[i], str_buf[i], sizeof(str_buf[i]));
559*d83cc019SAndroid Build Coastguard Worker 		crtc_strs[i] = &str_buf[i][0];
560*d83cc019SAndroid Build Coastguard Worker 	}
561*d83cc019SAndroid Build Coastguard Worker 
562*d83cc019SAndroid Build Coastguard Worker 	if (dry_run) {
563*d83cc019SAndroid Build Coastguard Worker 		for (i = 0; i < crtc_count; i++)
564*d83cc019SAndroid Build Coastguard Worker 			igt_info("    %s\n", crtc_strs[i]);
565*d83cc019SAndroid Build Coastguard Worker 		return;
566*d83cc019SAndroid Build Coastguard Worker 	}
567*d83cc019SAndroid Build Coastguard Worker 
568*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < crtc_count; i++) {
569*d83cc019SAndroid Build Coastguard Worker 		uint32_t *ids;
570*d83cc019SAndroid Build Coastguard Worker 
571*d83cc019SAndroid Build Coastguard Worker 		crtc = &crtcs[i];
572*d83cc019SAndroid Build Coastguard Worker 
573*d83cc019SAndroid Build Coastguard Worker 		igt_info("    %s\n", crtc_strs[i]);
574*d83cc019SAndroid Build Coastguard Worker 
575*d83cc019SAndroid Build Coastguard Worker 		create_fb_for_crtc(crtc, &crtc->fb_info);
576*d83cc019SAndroid Build Coastguard Worker #if defined(USE_CAIRO_PIXMAN)
577*d83cc019SAndroid Build Coastguard Worker 		paint_fb(&crtc->fb_info, tconf->name, crtc_strs, crtc_count, i);
578*d83cc019SAndroid Build Coastguard Worker #endif
579*d83cc019SAndroid Build Coastguard Worker 
580*d83cc019SAndroid Build Coastguard Worker 		ids = get_connector_ids(crtc);
581*d83cc019SAndroid Build Coastguard Worker 		if (tconf->flags & TEST_STEALING)
582*d83cc019SAndroid Build Coastguard Worker 			ret = test_stealing(drm_fd, crtc, ids);
583*d83cc019SAndroid Build Coastguard Worker 		else
584*d83cc019SAndroid Build Coastguard Worker 			ret = drmModeSetCrtc(drm_fd, crtc->crtc_id,
585*d83cc019SAndroid Build Coastguard Worker 					     crtc->fb_info.fb_id, 0, 0, ids,
586*d83cc019SAndroid Build Coastguard Worker 					     crtc->connector_count, &crtc->mode);
587*d83cc019SAndroid Build Coastguard Worker 
588*d83cc019SAndroid Build Coastguard Worker 		free(ids);
589*d83cc019SAndroid Build Coastguard Worker 
590*d83cc019SAndroid Build Coastguard Worker 		if (ret < 0) {
591*d83cc019SAndroid Build Coastguard Worker 			igt_assert_eq(errno, EINVAL);
592*d83cc019SAndroid Build Coastguard Worker 			config_failed = true;
593*d83cc019SAndroid Build Coastguard Worker 		}
594*d83cc019SAndroid Build Coastguard Worker 	}
595*d83cc019SAndroid Build Coastguard Worker 
596*d83cc019SAndroid Build Coastguard Worker 	igt_assert(config_failed == !!(tconf->flags & TEST_INVALID));
597*d83cc019SAndroid Build Coastguard Worker 
598*d83cc019SAndroid Build Coastguard Worker 	if (ret == 0 && tconf->flags & TEST_TIMINGS)
599*d83cc019SAndroid Build Coastguard Worker 		check_timings(crtcs[0].crtc_idx, &crtcs[0].mode);
600*d83cc019SAndroid Build Coastguard Worker 
601*d83cc019SAndroid Build Coastguard Worker 	return;
602*d83cc019SAndroid Build Coastguard Worker }
603*d83cc019SAndroid Build Coastguard Worker 
test_one_combination(const struct test_config * tconf,struct connector_config * cconfs,int connector_count)604*d83cc019SAndroid Build Coastguard Worker static void test_one_combination(const struct test_config *tconf,
605*d83cc019SAndroid Build Coastguard Worker 				 struct connector_config *cconfs,
606*d83cc019SAndroid Build Coastguard Worker 				 int connector_count)
607*d83cc019SAndroid Build Coastguard Worker {
608*d83cc019SAndroid Build Coastguard Worker 	struct crtc_config crtcs[MAX_CRTCS];
609*d83cc019SAndroid Build Coastguard Worker 	int crtc_count;
610*d83cc019SAndroid Build Coastguard Worker 	bool config_valid;
611*d83cc019SAndroid Build Coastguard Worker 
612*d83cc019SAndroid Build Coastguard Worker 	setup_crtcs(tconf->resources, cconfs, connector_count, crtcs,
613*d83cc019SAndroid Build Coastguard Worker 		    &crtc_count, &config_valid);
614*d83cc019SAndroid Build Coastguard Worker 
615*d83cc019SAndroid Build Coastguard Worker 	if (config_valid == !(tconf->flags & TEST_INVALID))
616*d83cc019SAndroid Build Coastguard Worker 		test_crtc_config(tconf, crtcs, crtc_count);
617*d83cc019SAndroid Build Coastguard Worker 
618*d83cc019SAndroid Build Coastguard Worker 	cleanup_crtcs(crtcs, crtc_count);
619*d83cc019SAndroid Build Coastguard Worker }
620*d83cc019SAndroid Build Coastguard Worker 
assign_crtc_to_connectors(const struct test_config * tconf,int * crtc_idxs,int connector_count,struct connector_config * cconfs)621*d83cc019SAndroid Build Coastguard Worker static int assign_crtc_to_connectors(const struct test_config *tconf,
622*d83cc019SAndroid Build Coastguard Worker 				     int *crtc_idxs, int connector_count,
623*d83cc019SAndroid Build Coastguard Worker 				     struct connector_config *cconfs)
624*d83cc019SAndroid Build Coastguard Worker {
625*d83cc019SAndroid Build Coastguard Worker 	unsigned long crtc_idx_mask;
626*d83cc019SAndroid Build Coastguard Worker 	int i;
627*d83cc019SAndroid Build Coastguard Worker 
628*d83cc019SAndroid Build Coastguard Worker 	crtc_idx_mask = 0;
629*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector_count; i++) {
630*d83cc019SAndroid Build Coastguard Worker 		int crtc_idx = crtc_idxs[i];
631*d83cc019SAndroid Build Coastguard Worker 
632*d83cc019SAndroid Build Coastguard Worker 		if ((tconf->flags & TEST_SINGLE_CRTC_CLONE) &&
633*d83cc019SAndroid Build Coastguard Worker 		    crtc_idx_mask & ~(1 << crtc_idx))
634*d83cc019SAndroid Build Coastguard Worker 			return -1;
635*d83cc019SAndroid Build Coastguard Worker 
636*d83cc019SAndroid Build Coastguard Worker 		if ((tconf->flags & TEST_EXCLUSIVE_CRTC_CLONE) &&
637*d83cc019SAndroid Build Coastguard Worker 		    crtc_idx_mask & (1 << crtc_idx))
638*d83cc019SAndroid Build Coastguard Worker 			return -1;
639*d83cc019SAndroid Build Coastguard Worker 
640*d83cc019SAndroid Build Coastguard Worker 		crtc_idx_mask |= 1 << crtc_idx;
641*d83cc019SAndroid Build Coastguard Worker 
642*d83cc019SAndroid Build Coastguard Worker 		cconfs[i].crtc_idx = crtc_idx;
643*d83cc019SAndroid Build Coastguard Worker 	}
644*d83cc019SAndroid Build Coastguard Worker 
645*d83cc019SAndroid Build Coastguard Worker 	return 0;
646*d83cc019SAndroid Build Coastguard Worker }
647*d83cc019SAndroid Build Coastguard Worker 
get_one_connector(drmModeRes * resources,int connector_id,struct connector_config * cconf)648*d83cc019SAndroid Build Coastguard Worker static int get_one_connector(drmModeRes *resources, int connector_id,
649*d83cc019SAndroid Build Coastguard Worker 			     struct connector_config *cconf)
650*d83cc019SAndroid Build Coastguard Worker {
651*d83cc019SAndroid Build Coastguard Worker 	drmModeConnector *connector;
652*d83cc019SAndroid Build Coastguard Worker 
653*d83cc019SAndroid Build Coastguard Worker 	connector = drmModeGetConnectorCurrent(drm_fd, connector_id);
654*d83cc019SAndroid Build Coastguard Worker 	igt_assert(connector);
655*d83cc019SAndroid Build Coastguard Worker 	cconf->connector = connector;
656*d83cc019SAndroid Build Coastguard Worker 
657*d83cc019SAndroid Build Coastguard Worker 	if (connector->connection != DRM_MODE_CONNECTED) {
658*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeConnector(connector);
659*d83cc019SAndroid Build Coastguard Worker 		return -1;
660*d83cc019SAndroid Build Coastguard Worker 	}
661*d83cc019SAndroid Build Coastguard Worker 
662*d83cc019SAndroid Build Coastguard Worker 	if (!kmstest_get_connector_default_mode(drm_fd, connector,
663*d83cc019SAndroid Build Coastguard Worker 						&cconf->default_mode)) {
664*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeConnector(connector);
665*d83cc019SAndroid Build Coastguard Worker 		return -1;
666*d83cc019SAndroid Build Coastguard Worker 	}
667*d83cc019SAndroid Build Coastguard Worker 
668*d83cc019SAndroid Build Coastguard Worker 	return 0;
669*d83cc019SAndroid Build Coastguard Worker }
670*d83cc019SAndroid Build Coastguard Worker 
get_connectors(drmModeRes * resources,int * connector_idxs,int connector_count,struct connector_config * cconfs)671*d83cc019SAndroid Build Coastguard Worker static int get_connectors(drmModeRes *resources, int *connector_idxs,
672*d83cc019SAndroid Build Coastguard Worker 			  int connector_count, struct connector_config *cconfs)
673*d83cc019SAndroid Build Coastguard Worker {
674*d83cc019SAndroid Build Coastguard Worker 	int i;
675*d83cc019SAndroid Build Coastguard Worker 
676*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector_count; i++) {
677*d83cc019SAndroid Build Coastguard Worker 		int connector_idx;
678*d83cc019SAndroid Build Coastguard Worker 		int connector_id;
679*d83cc019SAndroid Build Coastguard Worker 
680*d83cc019SAndroid Build Coastguard Worker 		connector_idx = connector_idxs[i];
681*d83cc019SAndroid Build Coastguard Worker 		igt_assert_lt(connector_idx, resources->count_connectors);
682*d83cc019SAndroid Build Coastguard Worker 		connector_id = resources->connectors[connector_idx];
683*d83cc019SAndroid Build Coastguard Worker 
684*d83cc019SAndroid Build Coastguard Worker 		if (get_one_connector(resources, connector_id, &cconfs[i]) < 0)
685*d83cc019SAndroid Build Coastguard Worker 			goto err;
686*d83cc019SAndroid Build Coastguard Worker 
687*d83cc019SAndroid Build Coastguard Worker 	}
688*d83cc019SAndroid Build Coastguard Worker 
689*d83cc019SAndroid Build Coastguard Worker 	return 0;
690*d83cc019SAndroid Build Coastguard Worker 
691*d83cc019SAndroid Build Coastguard Worker err:
692*d83cc019SAndroid Build Coastguard Worker 	while (i--)
693*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeConnector(cconfs[i].connector);
694*d83cc019SAndroid Build Coastguard Worker 
695*d83cc019SAndroid Build Coastguard Worker 	return -1;
696*d83cc019SAndroid Build Coastguard Worker }
697*d83cc019SAndroid Build Coastguard Worker 
free_connectors(struct connector_config * cconfs,int connector_count)698*d83cc019SAndroid Build Coastguard Worker static void free_connectors(struct connector_config *cconfs,
699*d83cc019SAndroid Build Coastguard Worker 			    int connector_count)
700*d83cc019SAndroid Build Coastguard Worker {
701*d83cc019SAndroid Build Coastguard Worker 	int i;
702*d83cc019SAndroid Build Coastguard Worker 
703*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector_count; i++)
704*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeConnector(cconfs[i].connector);
705*d83cc019SAndroid Build Coastguard Worker }
706*d83cc019SAndroid Build Coastguard Worker 
707*d83cc019SAndroid Build Coastguard Worker struct combination {
708*d83cc019SAndroid Build Coastguard Worker 	int elems[MAX_COMBINATION_ELEMS];
709*d83cc019SAndroid Build Coastguard Worker };
710*d83cc019SAndroid Build Coastguard Worker 
711*d83cc019SAndroid Build Coastguard Worker struct combination_set {
712*d83cc019SAndroid Build Coastguard Worker 	int count;
713*d83cc019SAndroid Build Coastguard Worker 	int capacity;
714*d83cc019SAndroid Build Coastguard Worker 	struct combination *items;
715*d83cc019SAndroid Build Coastguard Worker };
716*d83cc019SAndroid Build Coastguard Worker 
717*d83cc019SAndroid Build Coastguard Worker /*
718*d83cc019SAndroid Build Coastguard Worker  * Get all possible selection of k elements from n elements with or without
719*d83cc019SAndroid Build Coastguard Worker  * repetitions.
720*d83cc019SAndroid Build Coastguard Worker  */
iterate_combinations(int n,int k,bool allow_repetitions,int depth,int base,struct combination * comb,struct combination_set * set)721*d83cc019SAndroid Build Coastguard Worker static void iterate_combinations(int n, int k, bool allow_repetitions,
722*d83cc019SAndroid Build Coastguard Worker 				 int depth, int base, struct combination *comb,
723*d83cc019SAndroid Build Coastguard Worker 				 struct combination_set *set)
724*d83cc019SAndroid Build Coastguard Worker {
725*d83cc019SAndroid Build Coastguard Worker 	int v;
726*d83cc019SAndroid Build Coastguard Worker 
727*d83cc019SAndroid Build Coastguard Worker 	if (!k) {
728*d83cc019SAndroid Build Coastguard Worker 		igt_assert(set->count < set->capacity);
729*d83cc019SAndroid Build Coastguard Worker 		set->items[set->count++] = *comb;
730*d83cc019SAndroid Build Coastguard Worker 		return;
731*d83cc019SAndroid Build Coastguard Worker 	}
732*d83cc019SAndroid Build Coastguard Worker 
733*d83cc019SAndroid Build Coastguard Worker 	for (v = base; v < n; v++) {
734*d83cc019SAndroid Build Coastguard Worker 		comb->elems[depth] = v;
735*d83cc019SAndroid Build Coastguard Worker 		iterate_combinations(n, k - 1, allow_repetitions,
736*d83cc019SAndroid Build Coastguard Worker 				     depth + 1, allow_repetitions ? 0 : v + 1,
737*d83cc019SAndroid Build Coastguard Worker 				     comb, set);
738*d83cc019SAndroid Build Coastguard Worker 	}
739*d83cc019SAndroid Build Coastguard Worker 
740*d83cc019SAndroid Build Coastguard Worker }
741*d83cc019SAndroid Build Coastguard Worker 
get_combinations(int n,int k,bool allow_repetitions,struct combination_set * set)742*d83cc019SAndroid Build Coastguard Worker static void get_combinations(int n, int k, bool allow_repetitions,
743*d83cc019SAndroid Build Coastguard Worker 			     struct combination_set *set)
744*d83cc019SAndroid Build Coastguard Worker {
745*d83cc019SAndroid Build Coastguard Worker 	struct combination comb;
746*d83cc019SAndroid Build Coastguard Worker 
747*d83cc019SAndroid Build Coastguard Worker 	igt_assert(k <= ARRAY_SIZE(set->items[0].elems));
748*d83cc019SAndroid Build Coastguard Worker 	set->count = 0;
749*d83cc019SAndroid Build Coastguard Worker 	iterate_combinations(n, k, allow_repetitions, 0, 0, &comb, set);
750*d83cc019SAndroid Build Coastguard Worker }
751*d83cc019SAndroid Build Coastguard Worker 
test_combinations(const struct test_config * tconf,int connector_count)752*d83cc019SAndroid Build Coastguard Worker static void test_combinations(const struct test_config *tconf,
753*d83cc019SAndroid Build Coastguard Worker 			      int connector_count)
754*d83cc019SAndroid Build Coastguard Worker {
755*d83cc019SAndroid Build Coastguard Worker 	struct combination_set connector_combs;
756*d83cc019SAndroid Build Coastguard Worker 	struct combination_set crtc_combs;
757*d83cc019SAndroid Build Coastguard Worker 	struct connector_config *cconfs;
758*d83cc019SAndroid Build Coastguard Worker 	int i;
759*d83cc019SAndroid Build Coastguard Worker 
760*d83cc019SAndroid Build Coastguard Worker 	if (connector_count > 2 && (tconf->flags & TEST_STEALING))
761*d83cc019SAndroid Build Coastguard Worker 		return;
762*d83cc019SAndroid Build Coastguard Worker 
763*d83cc019SAndroid Build Coastguard Worker 	igt_assert(tconf->resources);
764*d83cc019SAndroid Build Coastguard Worker 
765*d83cc019SAndroid Build Coastguard Worker 	connector_combs.capacity = pow(tconf->resources->count_connectors,
766*d83cc019SAndroid Build Coastguard Worker 				       tconf->resources->count_crtcs + 1);
767*d83cc019SAndroid Build Coastguard Worker 	crtc_combs.capacity = pow(tconf->resources->count_crtcs,
768*d83cc019SAndroid Build Coastguard Worker 				  tconf->resources->count_crtcs + 1);
769*d83cc019SAndroid Build Coastguard Worker 
770*d83cc019SAndroid Build Coastguard Worker 	connector_combs.items = malloc(connector_combs.capacity * sizeof(struct combination));
771*d83cc019SAndroid Build Coastguard Worker 	crtc_combs.items = malloc(crtc_combs.capacity * sizeof(struct combination));
772*d83cc019SAndroid Build Coastguard Worker 
773*d83cc019SAndroid Build Coastguard Worker 	get_combinations(tconf->resources->count_connectors, connector_count,
774*d83cc019SAndroid Build Coastguard Worker 			 false, &connector_combs);
775*d83cc019SAndroid Build Coastguard Worker 	get_combinations(tconf->resources->count_crtcs, connector_count,
776*d83cc019SAndroid Build Coastguard Worker 			 true, &crtc_combs);
777*d83cc019SAndroid Build Coastguard Worker 
778*d83cc019SAndroid Build Coastguard Worker 	igt_info("Testing: %s %d connector combinations\n", tconf->name,
779*d83cc019SAndroid Build Coastguard Worker 		 connector_count);
780*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < connector_combs.count; i++) {
781*d83cc019SAndroid Build Coastguard Worker 		int *connector_idxs;
782*d83cc019SAndroid Build Coastguard Worker 		int ret;
783*d83cc019SAndroid Build Coastguard Worker 		int j;
784*d83cc019SAndroid Build Coastguard Worker 
785*d83cc019SAndroid Build Coastguard Worker 		cconfs = malloc(sizeof(*cconfs) * connector_count);
786*d83cc019SAndroid Build Coastguard Worker 		igt_assert(cconfs);
787*d83cc019SAndroid Build Coastguard Worker 
788*d83cc019SAndroid Build Coastguard Worker 		connector_idxs = &connector_combs.items[i].elems[0];
789*d83cc019SAndroid Build Coastguard Worker 		ret = get_connectors(tconf->resources, connector_idxs,
790*d83cc019SAndroid Build Coastguard Worker 				     connector_count, cconfs);
791*d83cc019SAndroid Build Coastguard Worker 		if (ret < 0)
792*d83cc019SAndroid Build Coastguard Worker 			goto free_cconfs;
793*d83cc019SAndroid Build Coastguard Worker 
794*d83cc019SAndroid Build Coastguard Worker 		for (j = 0; j < crtc_combs.count; j++) {
795*d83cc019SAndroid Build Coastguard Worker 			int *crtc_idxs = &crtc_combs.items[j].elems[0];
796*d83cc019SAndroid Build Coastguard Worker 			ret = assign_crtc_to_connectors(tconf, crtc_idxs,
797*d83cc019SAndroid Build Coastguard Worker 							connector_count,
798*d83cc019SAndroid Build Coastguard Worker 						        cconfs);
799*d83cc019SAndroid Build Coastguard Worker 			if (ret < 0)
800*d83cc019SAndroid Build Coastguard Worker 				continue;
801*d83cc019SAndroid Build Coastguard Worker 
802*d83cc019SAndroid Build Coastguard Worker 			test_one_combination(tconf, cconfs, connector_count);
803*d83cc019SAndroid Build Coastguard Worker 		}
804*d83cc019SAndroid Build Coastguard Worker 
805*d83cc019SAndroid Build Coastguard Worker 		free_connectors(cconfs, connector_count);
806*d83cc019SAndroid Build Coastguard Worker free_cconfs:
807*d83cc019SAndroid Build Coastguard Worker 		free(cconfs);
808*d83cc019SAndroid Build Coastguard Worker 	}
809*d83cc019SAndroid Build Coastguard Worker 
810*d83cc019SAndroid Build Coastguard Worker 	free(connector_combs.items);
811*d83cc019SAndroid Build Coastguard Worker 	free(crtc_combs.items);
812*d83cc019SAndroid Build Coastguard Worker }
813*d83cc019SAndroid Build Coastguard Worker 
run_test(const struct test_config * tconf)814*d83cc019SAndroid Build Coastguard Worker static void run_test(const struct test_config *tconf)
815*d83cc019SAndroid Build Coastguard Worker {
816*d83cc019SAndroid Build Coastguard Worker 	int connector_num;
817*d83cc019SAndroid Build Coastguard Worker 
818*d83cc019SAndroid Build Coastguard Worker 	connector_num = tconf->flags & TEST_CLONE ? 2 : 1;
819*d83cc019SAndroid Build Coastguard Worker 	for (; connector_num <= tconf->resources->count_crtcs; connector_num++)
820*d83cc019SAndroid Build Coastguard Worker 		test_combinations(tconf, connector_num);
821*d83cc019SAndroid Build Coastguard Worker }
822*d83cc019SAndroid Build Coastguard Worker 
opt_handler(int opt,int opt_index,void * data)823*d83cc019SAndroid Build Coastguard Worker static int opt_handler(int opt, int opt_index, void *data)
824*d83cc019SAndroid Build Coastguard Worker {
825*d83cc019SAndroid Build Coastguard Worker 	switch (opt) {
826*d83cc019SAndroid Build Coastguard Worker 	case 'd':
827*d83cc019SAndroid Build Coastguard Worker 		dry_run = true;
828*d83cc019SAndroid Build Coastguard Worker 		break;
829*d83cc019SAndroid Build Coastguard Worker 	case 't':
830*d83cc019SAndroid Build Coastguard Worker 		filter_test_id = atoi(optarg);
831*d83cc019SAndroid Build Coastguard Worker 		break;
832*d83cc019SAndroid Build Coastguard Worker 	default:
833*d83cc019SAndroid Build Coastguard Worker 		return IGT_OPT_HANDLER_ERROR;
834*d83cc019SAndroid Build Coastguard Worker 	}
835*d83cc019SAndroid Build Coastguard Worker 
836*d83cc019SAndroid Build Coastguard Worker 	return IGT_OPT_HANDLER_SUCCESS;
837*d83cc019SAndroid Build Coastguard Worker }
838*d83cc019SAndroid Build Coastguard Worker 
839*d83cc019SAndroid Build Coastguard Worker const char *help_str =
840*d83cc019SAndroid Build Coastguard Worker 	"  -d\t\tDon't run any test, only print what would be done. (still needs DRM access)\n"
841*d83cc019SAndroid Build Coastguard Worker 	"  -t <test id>\tRun only the test with this id.";
842*d83cc019SAndroid Build Coastguard Worker 
843*d83cc019SAndroid Build Coastguard Worker igt_main_args("dt:", NULL, help_str, opt_handler, NULL)
844*d83cc019SAndroid Build Coastguard Worker {
845*d83cc019SAndroid Build Coastguard Worker 	const struct {
846*d83cc019SAndroid Build Coastguard Worker 		enum test_flags flags;
847*d83cc019SAndroid Build Coastguard Worker 		const char *name;
848*d83cc019SAndroid Build Coastguard Worker 	} tests[] = {
849*d83cc019SAndroid Build Coastguard Worker 		{ TEST_TIMINGS, "basic" },
850*d83cc019SAndroid Build Coastguard Worker 		{ TEST_CLONE | TEST_SINGLE_CRTC_CLONE,
851*d83cc019SAndroid Build Coastguard Worker 					"basic-clone-single-crtc" },
852*d83cc019SAndroid Build Coastguard Worker 		{ TEST_INVALID | TEST_CLONE | TEST_SINGLE_CRTC_CLONE,
853*d83cc019SAndroid Build Coastguard Worker 					"invalid-clone-single-crtc" },
854*d83cc019SAndroid Build Coastguard Worker 		{ TEST_INVALID | TEST_CLONE | TEST_EXCLUSIVE_CRTC_CLONE,
855*d83cc019SAndroid Build Coastguard Worker 					"invalid-clone-exclusive-crtc" },
856*d83cc019SAndroid Build Coastguard Worker 		{ TEST_CLONE | TEST_EXCLUSIVE_CRTC_CLONE,
857*d83cc019SAndroid Build Coastguard Worker 					"clone-exclusive-crtc" },
858*d83cc019SAndroid Build Coastguard Worker 		{ TEST_INVALID | TEST_CLONE | TEST_SINGLE_CRTC_CLONE | TEST_STEALING,
859*d83cc019SAndroid Build Coastguard Worker 					"invalid-clone-single-crtc-stealing" }
860*d83cc019SAndroid Build Coastguard Worker 	};
861*d83cc019SAndroid Build Coastguard Worker 	int i;
862*d83cc019SAndroid Build Coastguard Worker 
863*d83cc019SAndroid Build Coastguard Worker 	igt_skip_on_simulation();
864*d83cc019SAndroid Build Coastguard Worker 
865*d83cc019SAndroid Build Coastguard Worker 	igt_assert_f(!(dry_run && filter_test_id),
866*d83cc019SAndroid Build Coastguard Worker 		     "only one of -d and -t is accepted\n");
867*d83cc019SAndroid Build Coastguard Worker 
868*d83cc019SAndroid Build Coastguard Worker 	igt_fixture {
869*d83cc019SAndroid Build Coastguard Worker 		drm_fd = drm_open_driver_master(DRIVER_ANY);
870*d83cc019SAndroid Build Coastguard Worker 		if (!dry_run)
871*d83cc019SAndroid Build Coastguard Worker 			kmstest_set_vt_graphics_mode();
872*d83cc019SAndroid Build Coastguard Worker 
873*d83cc019SAndroid Build Coastguard Worker 		drm_resources = drmModeGetResources(drm_fd);
874*d83cc019SAndroid Build Coastguard Worker 		igt_require(drm_resources);
875*d83cc019SAndroid Build Coastguard Worker 	}
876*d83cc019SAndroid Build Coastguard Worker 
877*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
878*d83cc019SAndroid Build Coastguard Worker 		igt_subtest(tests[i].name) {
879*d83cc019SAndroid Build Coastguard Worker 			struct test_config tconf = {
880*d83cc019SAndroid Build Coastguard Worker 				.flags		= tests[i].flags,
881*d83cc019SAndroid Build Coastguard Worker 				.name		= tests[i].name,
882*d83cc019SAndroid Build Coastguard Worker 				.resources	= drm_resources,
883*d83cc019SAndroid Build Coastguard Worker 			};
884*d83cc019SAndroid Build Coastguard Worker 			run_test(&tconf);
885*d83cc019SAndroid Build Coastguard Worker 		}
886*d83cc019SAndroid Build Coastguard Worker 	}
887*d83cc019SAndroid Build Coastguard Worker 
888*d83cc019SAndroid Build Coastguard Worker 	igt_fixture {
889*d83cc019SAndroid Build Coastguard Worker 		drmModeFreeResources(drm_resources);
890*d83cc019SAndroid Build Coastguard Worker 
891*d83cc019SAndroid Build Coastguard Worker 		close(drm_fd);
892*d83cc019SAndroid Build Coastguard Worker 	}
893*d83cc019SAndroid Build Coastguard Worker }
894