• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  * 	Daniel Vetter <daniel.vetter@ffwll.ch>
25  * 	Damien Lespiau <damien.lespiau@intel.com>
26  */
27 
28 #include "config.h"
29 
30 #include <assert.h>
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <stdlib.h>
40 #ifdef HAVE_LINUX_KD_H
41 #include <linux/kd.h>
42 #elif HAVE_SYS_KD_H
43 #include <sys/kd.h>
44 #endif
45 
46 #if !defined(ANDROID)
47 #include <libudev.h>
48 #endif
49 
50 #include <poll.h>
51 #include <errno.h>
52 #include <time.h>
53 
54 #include <i915_drm.h>
55 
56 #include "drmtest.h"
57 #include "igt_kms.h"
58 #include "igt_aux.h"
59 #include "igt_edid.h"
60 #include "intel_chipset.h"
61 #include "igt_debugfs.h"
62 #include "igt_device.h"
63 #include "igt_sysfs.h"
64 #include "sw_sync.h"
65 
66 /**
67  * SECTION:igt_kms
68  * @short_description: Kernel modesetting support library
69  * @title: KMS
70  * @include: igt.h
71  *
72  * This library provides support to enumerate and set modeset configurations.
73  *
74  * There are two parts in this library: First the low level helper function
75  * which directly build on top of raw ioctls or the interfaces provided by
76  * libdrm. Those functions all have a kmstest_ prefix.
77  *
78  * The second part is a high-level library to manage modeset configurations
79  * which abstracts away some of the low-level details like the difference
80  * between legacy and universal plane support for setting cursors or in the
81  * future the difference between legacy and atomic commit. These high-level
82  * functions have all igt_ prefixes. This part is still very much work in
83  * progress and so also lacks a bit documentation for the individual functions.
84  *
85  * Note that this library's header pulls in the [i-g-t framebuffer](igt-gpu-tools-i-g-t-framebuffer.html)
86  * library as a dependency.
87  */
88 
89 /* list of connectors that need resetting on exit */
90 #define MAX_CONNECTORS 32
91 static char *forced_connectors[MAX_CONNECTORS + 1];
92 static int forced_connectors_device[MAX_CONNECTORS + 1];
93 
94 /**
95  * igt_kms_get_base_edid:
96  *
97  * Get the base edid block, which includes the following modes:
98  *
99  *  - 1920x1080 60Hz
100  *  - 1280x720 60Hz
101  *  - 1024x768 60Hz
102  *  - 800x600 60Hz
103  *  - 640x480 60Hz
104  *
105  * Returns: a basic edid block
106  */
igt_kms_get_base_edid(void)107 const struct edid *igt_kms_get_base_edid(void)
108 {
109 	static struct edid edid;
110 	drmModeModeInfo mode = {};
111 
112 	mode.clock = 148500;
113 	mode.hdisplay = 1920;
114 	mode.hsync_start = 2008;
115 	mode.hsync_end = 2052;
116 	mode.htotal = 2200;
117 	mode.vdisplay = 1080;
118 	mode.vsync_start = 1084;
119 	mode.vsync_end = 1089;
120 	mode.vtotal = 1125;
121 	mode.vrefresh = 60;
122 
123 	edid_init_with_mode(&edid, &mode);
124 	edid_update_checksum(&edid);
125 
126 	return &edid;
127 }
128 
129 /**
130  * igt_kms_get_alt_edid:
131  *
132  * Get an alternate edid block, which includes the following modes:
133  *
134  *  - 1400x1050 60Hz
135  *  - 1920x1080 60Hz
136  *  - 1280x720 60Hz
137  *  - 1024x768 60Hz
138  *  - 800x600 60Hz
139  *  - 640x480 60Hz
140  *
141  * Returns: an alternate edid block
142  */
igt_kms_get_alt_edid(void)143 const struct edid *igt_kms_get_alt_edid(void)
144 {
145 	static struct edid edid;
146 	drmModeModeInfo mode = {};
147 
148 	mode.clock = 101000;
149 	mode.hdisplay = 1400;
150 	mode.hsync_start = 1448;
151 	mode.hsync_end = 1480;
152 	mode.htotal = 1560;
153 	mode.vdisplay = 1050;
154 	mode.vsync_start = 1053;
155 	mode.vsync_end = 1057;
156 	mode.vtotal = 1080;
157 	mode.vrefresh = 60;
158 
159 	edid_init_with_mode(&edid, &mode);
160 	edid_update_checksum(&edid);
161 
162 	return &edid;
163 }
164 
165 #define AUDIO_EDID_SIZE (2 * EDID_BLOCK_SIZE)
166 
167 static const struct edid *
generate_audio_edid(unsigned char raw_edid[static AUDIO_EDID_SIZE],bool with_vsdb,struct cea_sad * sad,struct cea_speaker_alloc * speaker_alloc)168 generate_audio_edid(unsigned char raw_edid[static AUDIO_EDID_SIZE],
169 		    bool with_vsdb, struct cea_sad *sad,
170 		    struct cea_speaker_alloc *speaker_alloc)
171 {
172 	struct edid *edid;
173 	struct edid_ext *edid_ext;
174 	struct edid_cea *edid_cea;
175 	char *cea_data;
176 	struct edid_cea_data_block *block;
177 	const struct cea_vsdb *vsdb;
178 	size_t cea_data_size, vsdb_size;
179 
180 	/* Create a new EDID from the base IGT EDID, and add an
181 	 * extension that advertises audio support. */
182 	edid = (struct edid *) raw_edid;
183 	memcpy(edid, igt_kms_get_base_edid(), sizeof(struct edid));
184 	edid->extensions_len = 1;
185 	edid_ext = &edid->extensions[0];
186 	edid_cea = &edid_ext->data.cea;
187 	cea_data = edid_cea->data;
188 	cea_data_size = 0;
189 
190 	/* Short Audio Descriptor block */
191 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
192 	cea_data_size += edid_cea_data_block_set_sad(block, sad, 1);
193 
194 	/* A Vendor Specific Data block is needed for HDMI audio */
195 	if (with_vsdb) {
196 		block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
197 		vsdb = cea_vsdb_get_hdmi_default(&vsdb_size);
198 		cea_data_size += edid_cea_data_block_set_vsdb(block, vsdb,
199 							      vsdb_size);
200 	}
201 
202 	/* Speaker Allocation Data block */
203 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
204 	cea_data_size += edid_cea_data_block_set_speaker_alloc(block,
205 							       speaker_alloc);
206 
207 	assert(cea_data_size <= sizeof(edid_cea->data));
208 
209 	edid_ext_set_cea(edid_ext, cea_data_size, 0, EDID_CEA_BASIC_AUDIO);
210 
211 	edid_update_checksum(edid);
212 
213 	return edid;
214 }
215 
igt_kms_get_hdmi_audio_edid(void)216 const struct edid *igt_kms_get_hdmi_audio_edid(void)
217 {
218 	int channels;
219 	uint8_t sampling_rates, sample_sizes;
220 	static unsigned char raw_edid[AUDIO_EDID_SIZE] = {0};
221 	struct cea_sad sad = {0};
222 	struct cea_speaker_alloc speaker_alloc = {0};
223 
224 	/* Initialize the Short Audio Descriptor for PCM */
225 	channels = 2;
226 	sampling_rates = CEA_SAD_SAMPLING_RATE_32KHZ |
227 			 CEA_SAD_SAMPLING_RATE_44KHZ |
228 			 CEA_SAD_SAMPLING_RATE_48KHZ;
229 	sample_sizes = CEA_SAD_SAMPLE_SIZE_16 |
230 		       CEA_SAD_SAMPLE_SIZE_20 |
231 		       CEA_SAD_SAMPLE_SIZE_24;
232 	cea_sad_init_pcm(&sad, channels, sampling_rates, sample_sizes);
233 
234 	/* Initialize the Speaker Allocation Data */
235 	speaker_alloc.speakers = CEA_SPEAKER_FRONT_LEFT_RIGHT_CENTER;
236 
237 	return generate_audio_edid(raw_edid, true, &sad, &speaker_alloc);
238 }
239 
igt_kms_get_dp_audio_edid(void)240 const struct edid *igt_kms_get_dp_audio_edid(void)
241 {
242 	int channels;
243 	uint8_t sampling_rates, sample_sizes;
244 	static unsigned char raw_edid[AUDIO_EDID_SIZE] = {0};
245 	struct cea_sad sad = {0};
246 	struct cea_speaker_alloc speaker_alloc = {0};
247 
248 	/* Initialize the Short Audio Descriptor for PCM */
249 	channels = 2;
250 	sampling_rates = CEA_SAD_SAMPLING_RATE_32KHZ |
251 			 CEA_SAD_SAMPLING_RATE_44KHZ |
252 			 CEA_SAD_SAMPLING_RATE_48KHZ;
253 	sample_sizes = CEA_SAD_SAMPLE_SIZE_16 |
254 		       CEA_SAD_SAMPLE_SIZE_20 |
255 		       CEA_SAD_SAMPLE_SIZE_24;
256 	cea_sad_init_pcm(&sad, channels, sampling_rates, sample_sizes);
257 
258 	/* Initialize the Speaker Allocation Data */
259 	speaker_alloc.speakers = CEA_SPEAKER_FRONT_LEFT_RIGHT_CENTER;
260 
261 	return generate_audio_edid(raw_edid, false, &sad, &speaker_alloc);
262 }
263 
264 static const uint8_t edid_4k_svds[] = {
265 	32 | CEA_SVD_NATIVE, /* 1080p @ 24Hz (native) */
266 	5,                   /* 1080i @ 60Hz */
267 	20,                  /* 1080i @ 50Hz */
268 	4,                   /* 720p @ 60Hz */
269 	19,                  /* 720p @ 50Hz */
270 };
271 
igt_kms_get_4k_edid(void)272 const struct edid *igt_kms_get_4k_edid(void)
273 {
274 	static unsigned char raw_edid[256] = {0};
275 	struct edid *edid;
276 	struct edid_ext *edid_ext;
277 	struct edid_cea *edid_cea;
278 	char *cea_data;
279 	struct edid_cea_data_block *block;
280 	/* We'll add 6 extension fields to the HDMI VSDB. */
281 	char raw_hdmi[HDMI_VSDB_MIN_SIZE + 6] = {0};
282 	struct hdmi_vsdb *hdmi;
283 	size_t cea_data_size = 0;
284 
285 	/* Create a new EDID from the base IGT EDID, and add an
286 	 * extension that advertises 4K support. */
287 	edid = (struct edid *) raw_edid;
288 	memcpy(edid, igt_kms_get_base_edid(), sizeof(struct edid));
289 	edid->extensions_len = 1;
290 	edid_ext = &edid->extensions[0];
291 	edid_cea = &edid_ext->data.cea;
292 	cea_data = edid_cea->data;
293 
294 	/* Short Video Descriptor */
295 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
296 	cea_data_size += edid_cea_data_block_set_svd(block, edid_4k_svds,
297 						     sizeof(edid_4k_svds));
298 
299 	/* Vendor-Specific Data Block */
300 	hdmi = (struct hdmi_vsdb *) raw_hdmi;
301 	hdmi->src_phy_addr[0] = 0x10;
302 	hdmi->src_phy_addr[1] = 0x00;
303 	/* 6 extension fields */
304 	hdmi->flags1 = 0;
305 	hdmi->max_tdms_clock = 0;
306 	hdmi->flags2 = HDMI_VSDB_VIDEO_PRESENT;
307 	hdmi->data[0] = 0x00; /* HDMI video flags */
308 	hdmi->data[1] = 1 << 5; /* 1 VIC entry, 0 3D entries */
309 	hdmi->data[2] = 0x01; /* 2160p, specified as short descriptor */
310 
311 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
312 	cea_data_size += edid_cea_data_block_set_hdmi_vsdb(block, hdmi,
313 							   sizeof(raw_hdmi));
314 
315 	assert(cea_data_size <= sizeof(edid_cea->data));
316 
317 	edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
318 
319 	edid_update_checksum(edid);
320 
321 	return edid;
322 }
323 
igt_kms_get_3d_edid(void)324 const struct edid *igt_kms_get_3d_edid(void)
325 {
326 	static unsigned char raw_edid[256] = {0};
327 	struct edid *edid;
328 	struct edid_ext *edid_ext;
329 	struct edid_cea *edid_cea;
330 	char *cea_data;
331 	struct edid_cea_data_block *block;
332 	/* We'll add 5 extension fields to the HDMI VSDB. */
333 	char raw_hdmi[HDMI_VSDB_MIN_SIZE + 5] = {0};
334 	struct hdmi_vsdb *hdmi;
335 	size_t cea_data_size = 0;
336 
337 	/* Create a new EDID from the base IGT EDID, and add an
338 	 * extension that advertises 3D support. */
339 	edid = (struct edid *) raw_edid;
340 	memcpy(edid, igt_kms_get_base_edid(), sizeof(struct edid));
341 	edid->extensions_len = 1;
342 	edid_ext = &edid->extensions[0];
343 	edid_cea = &edid_ext->data.cea;
344 	cea_data = edid_cea->data;
345 
346 	/* Short Video Descriptor */
347 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
348 	cea_data_size += edid_cea_data_block_set_svd(block, edid_4k_svds,
349 						     sizeof(edid_4k_svds));
350 
351 	/* Vendor-Specific Data Block */
352 	hdmi = (struct hdmi_vsdb *) raw_hdmi;
353 	hdmi->src_phy_addr[0] = 0x10;
354 	hdmi->src_phy_addr[1] = 0x00;
355 	/* 5 extension fields */
356 	hdmi->flags1 = 0;
357 	hdmi->max_tdms_clock = 0;
358 	hdmi->flags2 = HDMI_VSDB_VIDEO_PRESENT;
359 	hdmi->data[0] = HDMI_VSDB_VIDEO_3D_PRESENT; /* HDMI video flags */
360 	hdmi->data[1] = 0; /* 0 VIC entries, 0 3D entries */
361 
362 	block = (struct edid_cea_data_block *) &cea_data[cea_data_size];
363 	cea_data_size += edid_cea_data_block_set_hdmi_vsdb(block, hdmi,
364 							   sizeof(raw_hdmi));
365 
366 	assert(cea_data_size <= sizeof(edid_cea->data));
367 
368 	edid_ext_set_cea(edid_ext, cea_data_size, 0, 0);
369 
370 	edid_update_checksum(edid);
371 
372 	return edid;
373 }
374 
375 const char * const igt_plane_prop_names[IGT_NUM_PLANE_PROPS] = {
376 	[IGT_PLANE_SRC_X] = "SRC_X",
377 	[IGT_PLANE_SRC_Y] = "SRC_Y",
378 	[IGT_PLANE_SRC_W] = "SRC_W",
379 	[IGT_PLANE_SRC_H] = "SRC_H",
380 	[IGT_PLANE_CRTC_X] = "CRTC_X",
381 	[IGT_PLANE_CRTC_Y] = "CRTC_Y",
382 	[IGT_PLANE_CRTC_W] = "CRTC_W",
383 	[IGT_PLANE_CRTC_H] = "CRTC_H",
384 	[IGT_PLANE_FB_ID] = "FB_ID",
385 	[IGT_PLANE_CRTC_ID] = "CRTC_ID",
386 	[IGT_PLANE_IN_FENCE_FD] = "IN_FENCE_FD",
387 	[IGT_PLANE_TYPE] = "type",
388 	[IGT_PLANE_ROTATION] = "rotation",
389 	[IGT_PLANE_IN_FORMATS] = "IN_FORMATS",
390 	[IGT_PLANE_COLOR_ENCODING] = "COLOR_ENCODING",
391 	[IGT_PLANE_COLOR_RANGE] = "COLOR_RANGE",
392 	[IGT_PLANE_PIXEL_BLEND_MODE] = "pixel blend mode",
393 	[IGT_PLANE_ALPHA] = "alpha",
394 	[IGT_PLANE_ZPOS] = "zpos",
395 };
396 
397 const char * const igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = {
398 	[IGT_CRTC_BACKGROUND] = "background_color",
399 	[IGT_CRTC_CTM] = "CTM",
400 	[IGT_CRTC_GAMMA_LUT] = "GAMMA_LUT",
401 	[IGT_CRTC_GAMMA_LUT_SIZE] = "GAMMA_LUT_SIZE",
402 	[IGT_CRTC_DEGAMMA_LUT] = "DEGAMMA_LUT",
403 	[IGT_CRTC_DEGAMMA_LUT_SIZE] = "DEGAMMA_LUT_SIZE",
404 	[IGT_CRTC_MODE_ID] = "MODE_ID",
405 	[IGT_CRTC_ACTIVE] = "ACTIVE",
406 	[IGT_CRTC_OUT_FENCE_PTR] = "OUT_FENCE_PTR",
407 	[IGT_CRTC_VRR_ENABLED] = "VRR_ENABLED",
408 };
409 
410 const char * const igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
411 	[IGT_CONNECTOR_SCALING_MODE] = "scaling mode",
412 	[IGT_CONNECTOR_CRTC_ID] = "CRTC_ID",
413 	[IGT_CONNECTOR_DPMS] = "DPMS",
414 	[IGT_CONNECTOR_BROADCAST_RGB] = "Broadcast RGB",
415 	[IGT_CONNECTOR_CONTENT_PROTECTION] = "Content Protection",
416 	[IGT_CONNECTOR_VRR_CAPABLE] = "vrr_capable",
417 	[IGT_CONNECTOR_HDCP_CONTENT_TYPE] = "HDCP Content Type",
418 	[IGT_CONNECTOR_LINK_STATUS] = "link-status",
419 };
420 
421 /*
422  * Retrieve all the properies specified in props_name and store them into
423  * plane->props.
424  */
425 static void
igt_fill_plane_props(igt_display_t * display,igt_plane_t * plane,int num_props,const char * const prop_names[])426 igt_fill_plane_props(igt_display_t *display, igt_plane_t *plane,
427 		     int num_props, const char * const prop_names[])
428 {
429 	drmModeObjectPropertiesPtr props;
430 	int i, j, fd;
431 
432 	fd = display->drm_fd;
433 
434 	props = drmModeObjectGetProperties(fd, plane->drm_plane->plane_id, DRM_MODE_OBJECT_PLANE);
435 	igt_assert(props);
436 
437 	for (i = 0; i < props->count_props; i++) {
438 		drmModePropertyPtr prop =
439 			drmModeGetProperty(fd, props->props[i]);
440 
441 		for (j = 0; j < num_props; j++) {
442 			if (strcmp(prop->name, prop_names[j]) != 0)
443 				continue;
444 
445 			plane->props[j] = props->props[i];
446 			break;
447 		}
448 
449 		drmModeFreeProperty(prop);
450 	}
451 
452 	drmModeFreeObjectProperties(props);
453 }
454 
455 /*
456  * Retrieve all the properies specified in props_name and store them into
457  * config->atomic_props_crtc and config->atomic_props_connector.
458  */
459 static void
igt_atomic_fill_connector_props(igt_display_t * display,igt_output_t * output,int num_connector_props,const char * const conn_prop_names[])460 igt_atomic_fill_connector_props(igt_display_t *display, igt_output_t *output,
461 			int num_connector_props, const char * const conn_prop_names[])
462 {
463 	drmModeObjectPropertiesPtr props;
464 	int i, j, fd;
465 
466 	fd = display->drm_fd;
467 
468 	props = drmModeObjectGetProperties(fd, output->config.connector->connector_id, DRM_MODE_OBJECT_CONNECTOR);
469 	igt_assert(props);
470 
471 	for (i = 0; i < props->count_props; i++) {
472 		drmModePropertyPtr prop =
473 			drmModeGetProperty(fd, props->props[i]);
474 
475 		for (j = 0; j < num_connector_props; j++) {
476 			if (strcmp(prop->name, conn_prop_names[j]) != 0)
477 				continue;
478 
479 			output->props[j] = props->props[i];
480 			break;
481 		}
482 
483 		drmModeFreeProperty(prop);
484 	}
485 
486 	drmModeFreeObjectProperties(props);
487 }
488 
489 static void
igt_fill_pipe_props(igt_display_t * display,igt_pipe_t * pipe,int num_crtc_props,const char * const crtc_prop_names[])490 igt_fill_pipe_props(igt_display_t *display, igt_pipe_t *pipe,
491 		    int num_crtc_props, const char * const crtc_prop_names[])
492 {
493 	drmModeObjectPropertiesPtr props;
494 	int i, j, fd;
495 
496 	fd = display->drm_fd;
497 
498 	props = drmModeObjectGetProperties(fd, pipe->crtc_id, DRM_MODE_OBJECT_CRTC);
499 	igt_assert(props);
500 
501 	for (i = 0; i < props->count_props; i++) {
502 		drmModePropertyPtr prop =
503 			drmModeGetProperty(fd, props->props[i]);
504 
505 		for (j = 0; j < num_crtc_props; j++) {
506 			if (strcmp(prop->name, crtc_prop_names[j]) != 0)
507 				continue;
508 
509 			pipe->props[j] = props->props[i];
510 			break;
511 		}
512 
513 		drmModeFreeProperty(prop);
514 	}
515 
516 	drmModeFreeObjectProperties(props);
517 }
518 
519 /**
520  * kmstest_pipe_name:
521  * @pipe: display pipe
522  *
523  * Returns: String representing @pipe, e.g. "A".
524  */
kmstest_pipe_name(enum pipe pipe)525 const char *kmstest_pipe_name(enum pipe pipe)
526 {
527 	static const char str[] = "A\0B\0C\0D\0E\0F";
528 
529 	_Static_assert(sizeof(str) == IGT_MAX_PIPES * 2,
530 		       "Missing pipe name");
531 
532 	if (pipe == PIPE_NONE)
533 		return "None";
534 
535 	if (pipe >= IGT_MAX_PIPES)
536 		return "invalid";
537 
538 	return str + (pipe * 2);
539 }
540 
541 /**
542  * kmstest_pipe_to_index:
543  *@pipe: display pipe in string format
544  *
545  * Returns: index to corresponding pipe
546  */
kmstest_pipe_to_index(char pipe)547 int kmstest_pipe_to_index(char pipe)
548 {
549 	int r = pipe - 'A';
550 
551 	if (r < 0 || r >= IGT_MAX_PIPES)
552 		return -EINVAL;
553 
554 	return r;
555 }
556 
557 /**
558  * kmstest_plane_type_name:
559  * @plane_type: display plane type
560  *
561  * Returns: String representing @plane_type, e.g. "overlay".
562  */
kmstest_plane_type_name(int plane_type)563 const char *kmstest_plane_type_name(int plane_type)
564 {
565 	static const char * const names[] = {
566 		[DRM_PLANE_TYPE_OVERLAY] = "overlay",
567 		[DRM_PLANE_TYPE_PRIMARY] = "primary",
568 		[DRM_PLANE_TYPE_CURSOR] = "cursor",
569 	};
570 
571 	igt_assert(plane_type < ARRAY_SIZE(names) && names[plane_type]);
572 
573 	return names[plane_type];
574 }
575 
576 struct type_name {
577 	int type;
578 	const char *name;
579 };
580 
find_type_name(const struct type_name * names,int type)581 static const char *find_type_name(const struct type_name *names, int type)
582 {
583 	for (; names->name; names++) {
584 		if (names->type == type)
585 			return names->name;
586 	}
587 
588 	return "(invalid)";
589 }
590 
591 static const struct type_name encoder_type_names[] = {
592 	{ DRM_MODE_ENCODER_NONE, "none" },
593 	{ DRM_MODE_ENCODER_DAC, "DAC" },
594 	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
595 	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
596 	{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
597 	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
598 	{ DRM_MODE_ENCODER_DSI, "DSI" },
599 	{ DRM_MODE_ENCODER_DPMST, "DP MST" },
600 	{}
601 };
602 
603 /**
604  * kmstest_encoder_type_str:
605  * @type: DRM_MODE_ENCODER_* enumeration value
606  *
607  * Returns: A string representing the drm encoder @type.
608  */
kmstest_encoder_type_str(int type)609 const char *kmstest_encoder_type_str(int type)
610 {
611 	return find_type_name(encoder_type_names, type);
612 }
613 
614 static const struct type_name connector_status_names[] = {
615 	{ DRM_MODE_CONNECTED, "connected" },
616 	{ DRM_MODE_DISCONNECTED, "disconnected" },
617 	{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
618 	{}
619 };
620 
621 /**
622  * kmstest_connector_status_str:
623  * @status: DRM_MODE_* connector status value
624  *
625  * Returns: A string representing the drm connector status @status.
626  */
kmstest_connector_status_str(int status)627 const char *kmstest_connector_status_str(int status)
628 {
629 	return find_type_name(connector_status_names, status);
630 }
631 
632 static const struct type_name connector_type_names[] = {
633 	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
634 	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
635 	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
636 	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
637 	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
638 	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
639 	{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
640 	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
641 	{ DRM_MODE_CONNECTOR_Component, "Component" },
642 	{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
643 	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
644 	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
645 	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
646 	{ DRM_MODE_CONNECTOR_TV, "TV" },
647 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
648 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
649 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
650 	{ DRM_MODE_CONNECTOR_DPI, "DPI" },
651 	{}
652 };
653 
654 /**
655  * kmstest_connector_type_str:
656  * @type: DRM_MODE_CONNECTOR_* enumeration value
657  *
658  * Returns: A string representing the drm connector @type.
659  */
kmstest_connector_type_str(int type)660 const char *kmstest_connector_type_str(int type)
661 {
662 	return find_type_name(connector_type_names, type);
663 }
664 
mode_stereo_name(const drmModeModeInfo * mode)665 static const char *mode_stereo_name(const drmModeModeInfo *mode)
666 {
667 	switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
668 	case DRM_MODE_FLAG_3D_FRAME_PACKING:
669 		return "FP";
670 	case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
671 		return "FA";
672 	case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
673 		return "LA";
674 	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
675 		return "SBSF";
676 	case DRM_MODE_FLAG_3D_L_DEPTH:
677 		return "LD";
678 	case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
679 		return "LDGFX";
680 	case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
681 		return "TB";
682 	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
683 		return "SBSH";
684 	default:
685 		return NULL;
686 	}
687 }
688 
mode_picture_aspect_name(const drmModeModeInfo * mode)689 static const char *mode_picture_aspect_name(const drmModeModeInfo *mode)
690 {
691 	switch (mode->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
692 	case DRM_MODE_FLAG_PIC_AR_NONE:
693 		return NULL;
694 	case DRM_MODE_FLAG_PIC_AR_4_3:
695 		return "4:3";
696 	case DRM_MODE_FLAG_PIC_AR_16_9:
697 		return "16:9";
698 	case DRM_MODE_FLAG_PIC_AR_64_27:
699 		return "64:27";
700 	case DRM_MODE_FLAG_PIC_AR_256_135:
701 		return "256:135";
702 	default:
703 		return "invalid";
704 	}
705 }
706 
707 /**
708  * kmstest_dump_mode:
709  * @mode: libdrm mode structure
710  *
711  * Prints @mode to stdout in a human-readable form.
712  */
kmstest_dump_mode(drmModeModeInfo * mode)713 void kmstest_dump_mode(drmModeModeInfo *mode)
714 {
715 	const char *stereo = mode_stereo_name(mode);
716 	const char *aspect = mode_picture_aspect_name(mode);
717 
718 	igt_info("  %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s%s%s%s\n",
719 		 mode->name, mode->vrefresh,
720 		 mode->hdisplay, mode->hsync_start,
721 		 mode->hsync_end, mode->htotal,
722 		 mode->vdisplay, mode->vsync_start,
723 		 mode->vsync_end, mode->vtotal,
724 		 mode->flags, mode->type, mode->clock,
725 		 stereo ? " (3D:" : "",
726 		 stereo ? stereo : "", stereo ? ")" : "",
727 		 aspect ? " (PAR:" : "",
728 		 aspect ? aspect : "", aspect ? ")" : "");
729 }
730 
731 /**
732  * kmstest_get_pipe_from_crtc_id:
733  * @fd: DRM fd
734  * @crtc_id: DRM CRTC id
735  *
736  * Returns: The crtc index for the given DRM CRTC ID @crtc_id. The crtc index
737  * is the equivalent of the pipe id.  This value maps directly to an enum pipe
738  * value used in other helper functions.  Returns 0 if the index could not be
739  * determined.
740  */
741 
kmstest_get_pipe_from_crtc_id(int fd,int crtc_id)742 int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
743 {
744 	drmModeRes *res;
745 	drmModeCrtc *crtc;
746 	int i, cur_id;
747 
748 	res = drmModeGetResources(fd);
749 	igt_assert(res);
750 
751 	for (i = 0; i < res->count_crtcs; i++) {
752 		crtc = drmModeGetCrtc(fd, res->crtcs[i]);
753 		igt_assert(crtc);
754 		cur_id = crtc->crtc_id;
755 		drmModeFreeCrtc(crtc);
756 		if (cur_id == crtc_id)
757 			break;
758 	}
759 
760 	igt_assert(i < res->count_crtcs);
761 
762 	drmModeFreeResources(res);
763 
764 	return i;
765 }
766 
767 /**
768  * kmstest_find_crtc_for_connector:
769  * @fd: DRM fd
770  * @res: libdrm resources pointer
771  * @connector: libdrm connector pointer
772  * @crtc_blacklist_idx_mask: a mask of CRTC indexes that we can't return
773  *
774  * Returns: the CRTC ID for a CRTC that fits the connector, otherwise it asserts
775  * false and never returns. The blacklist mask can be used in case you have
776  * CRTCs that are already in use by other connectors.
777  */
kmstest_find_crtc_for_connector(int fd,drmModeRes * res,drmModeConnector * connector,uint32_t crtc_blacklist_idx_mask)778 uint32_t kmstest_find_crtc_for_connector(int fd, drmModeRes *res,
779 					 drmModeConnector *connector,
780 					 uint32_t crtc_blacklist_idx_mask)
781 {
782 	drmModeEncoder *e;
783 	uint32_t possible_crtcs;
784 	int i, j;
785 
786 	for (i = 0; i < connector->count_encoders; i++) {
787 		e = drmModeGetEncoder(fd, connector->encoders[i]);
788 		possible_crtcs = e->possible_crtcs & ~crtc_blacklist_idx_mask;
789 		drmModeFreeEncoder(e);
790 
791 		for (j = 0; possible_crtcs >> j; j++)
792 			if (possible_crtcs & (1 << j))
793 				return res->crtcs[j];
794 	}
795 
796 	igt_assert(false);
797 }
798 
799 /**
800  * kmstest_dumb_create:
801  * @fd: open drm file descriptor
802  * @width: width of the buffer in pixels
803  * @height: height of the buffer in pixels
804  * @bpp: bytes per pixel of the buffer
805  * @stride: Pointer which receives the dumb bo's stride, can be NULL.
806  * @size: Pointer which receives the dumb bo's size, can be NULL.
807  *
808  * This wraps the CREATE_DUMB ioctl, which allocates a new dumb buffer object
809  * for the specified dimensions.
810  *
811  * Returns: The file-private handle of the created buffer object
812  */
kmstest_dumb_create(int fd,int width,int height,int bpp,unsigned * stride,uint64_t * size)813 uint32_t kmstest_dumb_create(int fd, int width, int height, int bpp,
814 			     unsigned *stride, uint64_t *size)
815 {
816 	struct drm_mode_create_dumb create;
817 
818 	memset(&create, 0, sizeof(create));
819 	create.width = width;
820 	create.height = height;
821 	create.bpp = bpp;
822 
823 	create.handle = 0;
824 	do_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
825 	igt_assert(create.handle);
826 	igt_assert(create.size >= (uint64_t) width * height * bpp / 8);
827 
828 	if (stride)
829 		*stride = create.pitch;
830 
831 	if (size)
832 		*size = create.size;
833 
834 	return create.handle;
835 }
836 
837 /**
838  * kmstest_dumb_map_buffer:
839  * @fd: Opened drm file descriptor
840  * @handle: Offset in the file referred to by fd
841  * @size: Length of the mapping, must be greater than 0
842  * @prot: Describes the memory protection of the mapping
843  * Returns: A pointer representing the start of the virtual mapping
844  */
kmstest_dumb_map_buffer(int fd,uint32_t handle,uint64_t size,unsigned prot)845 void *kmstest_dumb_map_buffer(int fd, uint32_t handle, uint64_t size,
846 			      unsigned prot)
847 {
848 	struct drm_mode_map_dumb arg = {};
849 	void *ptr;
850 
851 	arg.handle = handle;
852 
853 	do_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
854 
855 	ptr = mmap(NULL, size, prot, MAP_SHARED, fd, arg.offset);
856 	igt_assert(ptr != MAP_FAILED);
857 
858 	return ptr;
859 }
860 
__kmstest_dumb_destroy(int fd,uint32_t handle)861 static int __kmstest_dumb_destroy(int fd, uint32_t handle)
862 {
863 	struct drm_mode_destroy_dumb arg = { handle };
864 	int err = 0;
865 
866 	if (drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg))
867 		err = -errno;
868 
869 	errno = 0;
870 	return err;
871 }
872 
873 /**
874  * kmstest_dumb_destroy:
875  * @fd: Opened drm file descriptor
876  * @handle: Offset in the file referred to by fd
877  */
kmstest_dumb_destroy(int fd,uint32_t handle)878 void kmstest_dumb_destroy(int fd, uint32_t handle)
879 {
880 	igt_assert_eq(__kmstest_dumb_destroy(fd, handle), 0);
881 }
882 
883 #if !defined(ANDROID)
884 /*
885  * Returns: the previous mode, or KD_GRAPHICS if no /dev/tty0 was
886  * found and nothing was done.
887  */
set_vt_mode(unsigned long mode)888 static signed long set_vt_mode(unsigned long mode)
889 {
890 	int fd;
891 	unsigned long prev_mode;
892 	static const char TTY0[] = "/dev/tty0";
893 
894 	if (access(TTY0, F_OK)) {
895 		/* errno message should be "No such file". Do not
896 		   hardcode but ask strerror() in the very unlikely
897 		   case something else happened. */
898 		igt_debug("VT: %s: %s, cannot change its mode\n",
899 			  TTY0, strerror(errno));
900 		return KD_GRAPHICS;
901 	}
902 
903 	fd = open(TTY0, O_RDONLY);
904 	if (fd < 0)
905 		return -errno;
906 
907 	prev_mode = 0;
908 	if (drmIoctl(fd, KDGETMODE, &prev_mode))
909 		goto err;
910 	if (drmIoctl(fd, KDSETMODE, (void *)mode))
911 		goto err;
912 
913 	close(fd);
914 
915 	return prev_mode;
916 err:
917 	close(fd);
918 
919 	return -errno;
920 }
921 #endif
922 
923 static unsigned long orig_vt_mode = -1UL;
924 
925 /**
926  * kmstest_restore_vt_mode:
927  *
928  * Restore the VT mode in use before #kmstest_set_vt_graphics_mode was called.
929  */
kmstest_restore_vt_mode(void)930 void kmstest_restore_vt_mode(void)
931 {
932 #if !defined(ANDROID)
933 	long ret;
934 
935 	if (orig_vt_mode != -1UL) {
936 		ret = set_vt_mode(orig_vt_mode);
937 
938 		igt_assert(ret >= 0);
939 		igt_debug("VT: original mode 0x%lx restored\n", orig_vt_mode);
940 		orig_vt_mode = -1UL;
941 	}
942 #endif
943 }
944 
945 /**
946  * kmstest_set_vt_graphics_mode:
947  *
948  * Sets the controlling VT (if available) into graphics/raw mode and installs
949  * an igt exit handler to set the VT back to text mode on exit. Use
950  * #kmstest_restore_vt_mode to restore the previous VT mode manually.
951  *
952  * All kms tests must call this function to make sure that the fbcon doesn't
953  * interfere by e.g. blanking the screen.
954  */
kmstest_set_vt_graphics_mode(void)955 void kmstest_set_vt_graphics_mode(void)
956 {
957 #if !defined(ANDROID)
958 	long ret;
959 
960 	igt_install_exit_handler((igt_exit_handler_t) kmstest_restore_vt_mode);
961 
962 	ret = set_vt_mode(KD_GRAPHICS);
963 
964 	igt_assert(ret >= 0);
965 	orig_vt_mode = ret;
966 
967 	igt_debug("VT: graphics mode set (mode was 0x%lx)\n", ret);
968 #endif
969 }
970 
971 
reset_connectors_at_exit(int sig)972 static void reset_connectors_at_exit(int sig)
973 {
974 	igt_reset_connectors();
975 }
976 
977 /**
978  * kmstest_force_connector:
979  * @fd: drm file descriptor
980  * @connector: connector
981  * @state: state to force on @connector
982  *
983  * Force the specified state on the specified connector.
984  *
985  * Returns: true on success
986  */
kmstest_force_connector(int drm_fd,drmModeConnector * connector,enum kmstest_force_connector_state state)987 bool kmstest_force_connector(int drm_fd, drmModeConnector *connector,
988 			     enum kmstest_force_connector_state state)
989 {
990 	char *path, **tmp;
991 	const char *value;
992 	drmModeConnector *temp;
993 	uint32_t devid;
994 	int len, dir, idx;
995 
996 #if defined(USE_INTEL)
997 	if (is_i915_device(drm_fd)) {
998 		devid = intel_get_drm_devid(drm_fd);
999 
1000 		/*
1001 		 * forcing hdmi or dp connectors on HSW and BDW doesn't
1002 		 * currently work, so fail early to allow the test to skip if
1003 		 * required
1004 		 */
1005 		if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
1006 		     connector->connector_type == DRM_MODE_CONNECTOR_HDMIB ||
1007 		     connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
1008 		    && (IS_HASWELL(devid) || IS_BROADWELL(devid)))
1009 			return false;
1010 	}
1011 #endif
1012 
1013 	switch (state) {
1014 	case FORCE_CONNECTOR_ON:
1015 		value = "on";
1016 		break;
1017 	case FORCE_CONNECTOR_DIGITAL:
1018 		value = "on-digital";
1019 		break;
1020 	case FORCE_CONNECTOR_OFF:
1021 		value = "off";
1022 		break;
1023 
1024 	default:
1025 	case FORCE_CONNECTOR_UNSPECIFIED:
1026 		value = "detect";
1027 		break;
1028 	}
1029 
1030 	dir = igt_sysfs_open(drm_fd);
1031 	if (dir < 0)
1032 		return false;
1033 
1034 	idx = igt_device_get_card_index(drm_fd);
1035 	if (idx < 0 || idx > 63)
1036 		return false;
1037 
1038 	if (asprintf(&path, "card%d-%s-%d/status",
1039 		     idx,
1040 		     kmstest_connector_type_str(connector->connector_type),
1041 		     connector->connector_type_id) < 0) {
1042 		close(dir);
1043 		return false;
1044 	}
1045 
1046 	if (!igt_sysfs_set(dir, path, value)) {
1047 		close(dir);
1048 		return false;
1049 	}
1050 
1051 	for (len = 0, tmp = forced_connectors; *tmp; tmp++) {
1052 		/* check the connector is not already present */
1053 		if (strcmp(*tmp, path) == 0) {
1054 			len = -1;
1055 			break;
1056 		}
1057 		len++;
1058 	}
1059 
1060 	if (len != -1 && len < MAX_CONNECTORS) {
1061 		forced_connectors[len] = path;
1062 		forced_connectors_device[len] = dir;
1063 	}
1064 
1065 	if (len >= MAX_CONNECTORS)
1066 		igt_warn("Connector limit reached, %s will not be reset\n",
1067 			 path);
1068 
1069 	igt_debug("Connector %s is now forced %s\n", path, value);
1070 	igt_debug("Current forced connectors:\n");
1071 	tmp = forced_connectors;
1072 	while (*tmp) {
1073 		igt_debug("\t%s\n", *tmp);
1074 		tmp++;
1075 	}
1076 
1077 	igt_install_exit_handler(reset_connectors_at_exit);
1078 
1079 	/* To allow callers to always use GetConnectorCurrent we need to force a
1080 	 * redetection here. */
1081 	temp = drmModeGetConnector(drm_fd, connector->connector_id);
1082 	drmModeFreeConnector(temp);
1083 
1084 	return true;
1085 }
1086 
1087 /**
1088  * kmstest_force_edid:
1089  * @drm_fd: drm file descriptor
1090  * @connector: connector to set @edid on
1091  * @edid: An EDID data block
1092  *
1093  * Set the EDID data on @connector to @edid. See also #igt_kms_get_base_edid.
1094  *
1095  * If @edid is NULL, the forced EDID will be removed.
1096  */
kmstest_force_edid(int drm_fd,drmModeConnector * connector,const struct edid * edid)1097 void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
1098 			const struct edid *edid)
1099 {
1100 	char *path;
1101 	int debugfs_fd, ret;
1102 	drmModeConnector *temp;
1103 
1104 	igt_assert_neq(asprintf(&path, "%s-%d/edid_override", kmstest_connector_type_str(connector->connector_type), connector->connector_type_id),
1105 		       -1);
1106 	debugfs_fd = igt_debugfs_open(drm_fd, path, O_WRONLY | O_TRUNC);
1107 	free(path);
1108 
1109 	igt_require(debugfs_fd != -1);
1110 
1111 	if (edid == NULL)
1112 		ret = write(debugfs_fd, "reset", 5);
1113 	else
1114 		ret = write(debugfs_fd, edid,
1115 			    edid_get_size(edid));
1116 	close(debugfs_fd);
1117 
1118 	/* To allow callers to always use GetConnectorCurrent we need to force a
1119 	 * redetection here. */
1120 	temp = drmModeGetConnector(drm_fd, connector->connector_id);
1121 	drmModeFreeConnector(temp);
1122 
1123 	igt_assert(ret != -1);
1124 }
1125 
1126 /**
1127  * kmstest_get_connector_default_mode:
1128  * @drm_fd: DRM fd
1129  * @connector: libdrm connector
1130  * @mode: libdrm mode
1131  *
1132  * Retrieves the default mode for @connector and stores it in @mode.
1133  *
1134  * Returns: true on success, false on failure
1135  */
kmstest_get_connector_default_mode(int drm_fd,drmModeConnector * connector,drmModeModeInfo * mode)1136 bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
1137 					drmModeModeInfo *mode)
1138 {
1139 	int i;
1140 
1141 	if (!connector->count_modes) {
1142 		igt_warn("no modes for connector %d\n",
1143 			 connector->connector_id);
1144 		return false;
1145 	}
1146 
1147 	for (i = 0; i < connector->count_modes; i++) {
1148 		if (i == 0 ||
1149 		    connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
1150 			*mode = connector->modes[i];
1151 			if (mode->type & DRM_MODE_TYPE_PREFERRED)
1152 				break;
1153 		}
1154 	}
1155 
1156 	return true;
1157 }
1158 
1159 static void
_kmstest_connector_config_crtc_mask(int drm_fd,drmModeConnector * connector,struct kmstest_connector_config * config)1160 _kmstest_connector_config_crtc_mask(int drm_fd,
1161 				    drmModeConnector *connector,
1162 				    struct kmstest_connector_config *config)
1163 {
1164 	int i;
1165 
1166 	config->valid_crtc_idx_mask = 0;
1167 
1168 	/* Now get a compatible encoder */
1169 	for (i = 0; i < connector->count_encoders; i++) {
1170 		drmModeEncoder *encoder = drmModeGetEncoder(drm_fd,
1171 							    connector->encoders[i]);
1172 
1173 		if (!encoder) {
1174 			igt_warn("could not get encoder %d: %s\n",
1175 				 connector->encoders[i],
1176 				 strerror(errno));
1177 
1178 			continue;
1179 		}
1180 
1181 		config->valid_crtc_idx_mask |= encoder->possible_crtcs;
1182 		drmModeFreeEncoder(encoder);
1183 	}
1184 }
1185 
1186 static drmModeEncoder *
_kmstest_connector_config_find_encoder(int drm_fd,drmModeConnector * connector,enum pipe pipe)1187 _kmstest_connector_config_find_encoder(int drm_fd, drmModeConnector *connector, enum pipe pipe)
1188 {
1189 	int i;
1190 
1191 	for (i = 0; i < connector->count_encoders; i++) {
1192 		drmModeEncoder *encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
1193 
1194 		if (!encoder) {
1195 			igt_warn("could not get encoder %d: %s\n",
1196 				 connector->encoders[i],
1197 				 strerror(errno));
1198 
1199 			continue;
1200 		}
1201 
1202 		if (encoder->possible_crtcs & (1 << pipe))
1203 			return encoder;
1204 
1205 		drmModeFreeEncoder(encoder);
1206 	}
1207 
1208 	igt_assert(false);
1209 	return NULL;
1210 }
1211 
1212 /**
1213  * _kmstest_connector_config:
1214  * @drm_fd: DRM fd
1215  * @connector_id: DRM connector id
1216  * @crtc_idx_mask: mask of allowed DRM CRTC indices
1217  * @config: structure filled with the possible configuration
1218  * @probe: whether to fully re-probe mode list or not
1219  *
1220  * This tries to find a suitable configuration for the given connector and CRTC
1221  * constraint and fills it into @config.
1222  */
_kmstest_connector_config(int drm_fd,uint32_t connector_id,unsigned long crtc_idx_mask,struct kmstest_connector_config * config,bool probe)1223 static bool _kmstest_connector_config(int drm_fd, uint32_t connector_id,
1224 				      unsigned long crtc_idx_mask,
1225 				      struct kmstest_connector_config *config,
1226 				      bool probe)
1227 {
1228 	drmModeRes *resources;
1229 	drmModeConnector *connector;
1230 
1231 	config->pipe = PIPE_NONE;
1232 
1233 	resources = drmModeGetResources(drm_fd);
1234 	if (!resources) {
1235 		igt_warn("drmModeGetResources failed");
1236 		goto err1;
1237 	}
1238 
1239 	/* First, find the connector & mode */
1240 	if (probe)
1241 		connector = drmModeGetConnector(drm_fd, connector_id);
1242 	else
1243 		connector = drmModeGetConnectorCurrent(drm_fd, connector_id);
1244 
1245 	if (!connector)
1246 		goto err2;
1247 
1248 	if (connector->connector_id != connector_id) {
1249 		igt_warn("connector id doesn't match (%d != %d)\n",
1250 			 connector->connector_id, connector_id);
1251 		goto err3;
1252 	}
1253 
1254 	/*
1255 	 * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
1256 	 * In both cases find the first compatible encoder and skip the CRTC
1257 	 * if there is non such.
1258 	 */
1259 	_kmstest_connector_config_crtc_mask(drm_fd, connector, config);
1260 
1261 	if (!connector->count_modes)
1262 		memset(&config->default_mode, 0, sizeof(config->default_mode));
1263 	else if (!kmstest_get_connector_default_mode(drm_fd, connector,
1264 						     &config->default_mode))
1265 		goto err3;
1266 
1267 	config->connector = connector;
1268 
1269 	crtc_idx_mask &= config->valid_crtc_idx_mask;
1270 	if (!crtc_idx_mask)
1271 		/* Keep config->connector */
1272 		goto err2;
1273 
1274 	config->pipe = ffs(crtc_idx_mask) - 1;
1275 
1276 	config->encoder = _kmstest_connector_config_find_encoder(drm_fd, connector, config->pipe);
1277 	config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[config->pipe]);
1278 
1279 	if (connector->connection != DRM_MODE_CONNECTED)
1280 		goto err2;
1281 
1282 	if (!connector->count_modes) {
1283 		if (probe)
1284 			igt_warn("connector %d/%s-%d has no modes\n", connector_id,
1285 				kmstest_connector_type_str(connector->connector_type),
1286 				connector->connector_type_id);
1287 		goto err2;
1288 	}
1289 
1290 	drmModeFreeResources(resources);
1291 	return true;
1292 err3:
1293 	drmModeFreeConnector(connector);
1294 err2:
1295 	drmModeFreeResources(resources);
1296 err1:
1297 	return false;
1298 }
1299 
1300 /**
1301  * kmstest_get_connector_config:
1302  * @drm_fd: DRM fd
1303  * @connector_id: DRM connector id
1304  * @crtc_idx_mask: mask of allowed DRM CRTC indices
1305  * @config: structure filled with the possible configuration
1306  *
1307  * This tries to find a suitable configuration for the given connector and CRTC
1308  * constraint and fills it into @config.
1309  */
kmstest_get_connector_config(int drm_fd,uint32_t connector_id,unsigned long crtc_idx_mask,struct kmstest_connector_config * config)1310 bool kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
1311 				  unsigned long crtc_idx_mask,
1312 				  struct kmstest_connector_config *config)
1313 {
1314 	return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
1315 					 config, 0);
1316 }
1317 
1318 /**
1319  * kmstest_probe_connector_config:
1320  * @drm_fd: DRM fd
1321  * @connector_id: DRM connector id
1322  * @crtc_idx_mask: mask of allowed DRM CRTC indices
1323  * @config: structure filled with the possible configuration
1324  *
1325  * This tries to find a suitable configuration for the given connector and CRTC
1326  * constraint and fills it into @config, fully probing the connector in the
1327  * process.
1328  */
kmstest_probe_connector_config(int drm_fd,uint32_t connector_id,unsigned long crtc_idx_mask,struct kmstest_connector_config * config)1329 bool kmstest_probe_connector_config(int drm_fd, uint32_t connector_id,
1330 				    unsigned long crtc_idx_mask,
1331 				    struct kmstest_connector_config *config)
1332 {
1333 	return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
1334 					 config, 1);
1335 }
1336 
1337 /**
1338  * kmstest_free_connector_config:
1339  * @config: connector configuration structure
1340  *
1341  * Free any resources in @config allocated in kmstest_get_connector_config().
1342  */
kmstest_free_connector_config(struct kmstest_connector_config * config)1343 void kmstest_free_connector_config(struct kmstest_connector_config *config)
1344 {
1345 	drmModeFreeCrtc(config->crtc);
1346 	config->crtc = NULL;
1347 
1348 	drmModeFreeEncoder(config->encoder);
1349 	config->encoder = NULL;
1350 
1351 	drmModeFreeConnector(config->connector);
1352 	config->connector = NULL;
1353 }
1354 
1355 /**
1356  * kmstest_set_connector_dpms:
1357  * @fd: DRM fd
1358  * @connector: libdrm connector
1359  * @mode: DRM DPMS value
1360  *
1361  * This function sets the DPMS setting of @connector to @mode.
1362  */
kmstest_set_connector_dpms(int fd,drmModeConnector * connector,int mode)1363 void kmstest_set_connector_dpms(int fd, drmModeConnector *connector, int mode)
1364 {
1365 	int i, dpms = 0;
1366 	bool found_it = false;
1367 
1368 	for (i = 0; i < connector->count_props; i++) {
1369 		struct drm_mode_get_property prop = {
1370 			.prop_id = connector->props[i],
1371 		};
1372 
1373 		if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
1374 			continue;
1375 
1376 		if (strcmp(prop.name, "DPMS"))
1377 			continue;
1378 
1379 		dpms = prop.prop_id;
1380 		found_it = true;
1381 		break;
1382 	}
1383 	igt_assert_f(found_it, "DPMS property not found on %d\n",
1384 		     connector->connector_id);
1385 
1386 	igt_assert(drmModeConnectorSetProperty(fd, connector->connector_id,
1387 					       dpms, mode) == 0);
1388 }
1389 
1390 /**
1391  * kmstest_get_property:
1392  * @drm_fd: drm file descriptor
1393  * @object_id: object whose properties we're going to get
1394  * @object_type: type of obj_id (DRM_MODE_OBJECT_*)
1395  * @name: name of the property we're going to get
1396  * @prop_id: if not NULL, returns the property id
1397  * @value: if not NULL, returns the property value
1398  * @prop: if not NULL, returns the property, and the caller will have to free
1399  *        it manually.
1400  *
1401  * Finds a property with the given name on the given object.
1402  *
1403  * Returns: true in case we found something.
1404  */
1405 bool
kmstest_get_property(int drm_fd,uint32_t object_id,uint32_t object_type,const char * name,uint32_t * prop_id,uint64_t * value,drmModePropertyPtr * prop)1406 kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type,
1407 		     const char *name, uint32_t *prop_id /* out */,
1408 		     uint64_t *value /* out */,
1409 		     drmModePropertyPtr *prop /* out */)
1410 {
1411 	drmModeObjectPropertiesPtr proplist;
1412 	drmModePropertyPtr _prop;
1413 	bool found = false;
1414 	int i;
1415 
1416 	proplist = drmModeObjectGetProperties(drm_fd, object_id, object_type);
1417 	for (i = 0; i < proplist->count_props; i++) {
1418 		_prop = drmModeGetProperty(drm_fd, proplist->props[i]);
1419 		if (!_prop)
1420 			continue;
1421 
1422 		if (strcmp(_prop->name, name) == 0) {
1423 			found = true;
1424 			if (prop_id)
1425 				*prop_id = proplist->props[i];
1426 			if (value)
1427 				*value = proplist->prop_values[i];
1428 			if (prop)
1429 				*prop = _prop;
1430 			else
1431 				drmModeFreeProperty(_prop);
1432 
1433 			break;
1434 		}
1435 		drmModeFreeProperty(_prop);
1436 	}
1437 
1438 	drmModeFreeObjectProperties(proplist);
1439 	return found;
1440 }
1441 
1442 /**
1443  * kmstest_unset_all_crtcs:
1444  * @drm_fd: the DRM fd
1445  * @resources: libdrm resources pointer
1446  *
1447  * Disables all the screens.
1448  */
kmstest_unset_all_crtcs(int drm_fd,drmModeResPtr resources)1449 void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources)
1450 {
1451 	int i, rc;
1452 
1453 	for (i = 0; i < resources->count_crtcs; i++) {
1454 		rc = drmModeSetCrtc(drm_fd, resources->crtcs[i], 0, 0, 0, NULL,
1455 				    0, NULL);
1456 		igt_assert(rc == 0);
1457 	}
1458 }
1459 
1460 /**
1461  * kmstest_get_crtc_idx:
1462  * @res: the libdrm resources
1463  * @crtc_id: the CRTC id
1464  *
1465  * Get the CRTC index based on its ID. This is useful since a few places of
1466  * libdrm deal with CRTC masks.
1467  */
kmstest_get_crtc_idx(drmModeRes * res,uint32_t crtc_id)1468 int kmstest_get_crtc_idx(drmModeRes *res, uint32_t crtc_id)
1469 {
1470 	int i;
1471 
1472 	for (i = 0; i < res->count_crtcs; i++)
1473 		if (res->crtcs[i] == crtc_id)
1474 			return i;
1475 
1476 	igt_assert(false);
1477 }
1478 
pipe_select(int pipe)1479 static inline uint32_t pipe_select(int pipe)
1480 {
1481 	if (pipe > 1)
1482 		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
1483 	else if (pipe > 0)
1484 		return DRM_VBLANK_SECONDARY;
1485 	else
1486 		return 0;
1487 }
1488 
1489 /**
1490  * kmstest_get_vblank:
1491  * @fd: Opened drm file descriptor
1492  * @pipe: Display pipe
1493  * @flags: Flags passed to drm_ioctl_wait_vblank
1494  *
1495  * Blocks or request a signal when a specified vblank event occurs
1496  *
1497  * Returns 0 on success or non-zero unsigned integer otherwise
1498  */
kmstest_get_vblank(int fd,int pipe,unsigned int flags)1499 unsigned int kmstest_get_vblank(int fd, int pipe, unsigned int flags)
1500 {
1501 	union drm_wait_vblank vbl;
1502 
1503 	memset(&vbl, 0, sizeof(vbl));
1504 	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags;
1505 	if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
1506 		return 0;
1507 
1508 	return vbl.reply.sequence;
1509 }
1510 
1511 /**
1512  * kmstest_wait_for_pageflip:
1513  * @fd: Opened drm file descriptor
1514  *
1515  * Blocks until pageflip is completed
1516  *
1517  */
kmstest_wait_for_pageflip(int fd)1518 void kmstest_wait_for_pageflip(int fd)
1519 {
1520 	drmEventContext evctx = { .version = 2 };
1521 	struct timeval timeout = { .tv_sec = 0, .tv_usec = 50000 };
1522 	fd_set fds;
1523 	int ret;
1524 
1525 	/* Wait for pageflip completion, then consume event on fd */
1526 	FD_ZERO(&fds);
1527 	FD_SET(fd, &fds);
1528 	do {
1529 		errno = 0;
1530 		ret = select(fd + 1, &fds, NULL, NULL, &timeout);
1531 	} while (ret < 0 && errno == EINTR);
1532 
1533 	igt_fail_on_f(ret == 0,
1534 		     "Exceeded timeout (50ms) while waiting for a pageflip\n");
1535 
1536 	igt_assert_f(ret == 1,
1537 		     "Waiting for pageflip failed with %d from select(drmfd)\n",
1538 		     ret);
1539 
1540 	igt_assert(drmHandleEvent(fd, &evctx) == 0);
1541 }
1542 
get_plane(char * str,int type,struct kmstest_plane * plane)1543 static void get_plane(char *str, int type, struct kmstest_plane *plane)
1544 {
1545 	int ret;
1546 	char buf[256];
1547 
1548 	plane->type = type;
1549 	ret = sscanf(str + 12, "%d%*c %*s %[^n]s",
1550 		     &plane->id,
1551 		     buf);
1552 	igt_assert_eq(ret, 2);
1553 
1554 	ret = sscanf(buf + 9, "%4d%*c%4d%*c", &plane->pos_x, &plane->pos_y);
1555 	igt_assert_eq(ret, 2);
1556 
1557 	ret = sscanf(buf + 30, "%4d%*c%4d%*c", &plane->width, &plane->height);
1558 	igt_assert_eq(ret, 2);
1559 }
1560 
parse_planes(FILE * fid,struct kmstest_plane * planes)1561 static int parse_planes(FILE *fid, struct kmstest_plane *planes)
1562 {
1563 	char tmp[256];
1564 	int n_planes;
1565 
1566 	n_planes = 0;
1567 	while (fgets(tmp, 256, fid) != NULL) {
1568 		if (strstr(tmp, "type=PRI") != NULL) {
1569 			if (planes) {
1570 				get_plane(tmp, DRM_PLANE_TYPE_PRIMARY, &planes[n_planes]);
1571 				planes[n_planes].index = n_planes;
1572 			}
1573 			n_planes++;
1574 		} else if (strstr(tmp, "type=OVL") != NULL) {
1575 			if (planes) {
1576 				get_plane(tmp, DRM_PLANE_TYPE_OVERLAY, &planes[n_planes]);
1577 				planes[n_planes].index = n_planes;
1578 			}
1579 			n_planes++;
1580 		} else if (strstr(tmp, "type=CUR") != NULL) {
1581 			if (planes) {
1582 				get_plane(tmp, DRM_PLANE_TYPE_CURSOR, &planes[n_planes]);
1583 				planes[n_planes].index = n_planes;
1584 			}
1585 			n_planes++;
1586 			break;
1587 		}
1588 	}
1589 
1590 	return n_planes;
1591 }
1592 
parse_crtc(char * info,struct kmstest_crtc * crtc)1593 static void parse_crtc(char *info, struct kmstest_crtc *crtc)
1594 {
1595 	char buf[256];
1596 	int ret;
1597 	char pipe;
1598 
1599 	ret = sscanf(info + 4, "%d%*c %*s %c%*c %*s %s%*c",
1600 		     &crtc->id, &pipe, buf);
1601 	igt_assert_eq(ret, 3);
1602 
1603 	crtc->pipe = kmstest_pipe_to_index(pipe);
1604 	igt_assert(crtc->pipe >= 0);
1605 
1606 	ret = sscanf(buf + 6, "%d%*c%d%*c",
1607 		     &crtc->width, &crtc->height);
1608 	igt_assert_eq(ret, 2);
1609 }
1610 
kmstest_get_crtc(int device,enum pipe pipe,struct kmstest_crtc * crtc)1611 static void kmstest_get_crtc(int device, enum pipe pipe, struct kmstest_crtc *crtc)
1612 {
1613 	char tmp[256];
1614 	FILE *file;
1615 	int ncrtc;
1616 	int line;
1617 	long int n;
1618 	int fd;
1619 
1620 	fd = igt_debugfs_open(device, "i915_display_info", O_RDONLY);
1621 	file = fdopen(fd, "r");
1622 	igt_skip_on(file == NULL);
1623 
1624 	ncrtc = 0;
1625 	line = 0;
1626 	while (fgets(tmp, 256, file) != NULL) {
1627 		if ((strstr(tmp, "CRTC") != NULL) && (line > 0)) {
1628 			if (strstr(tmp, "active=yes") != NULL) {
1629 				crtc->active = true;
1630 				parse_crtc(tmp, crtc);
1631 
1632 				n = ftell(file);
1633 				crtc->n_planes = parse_planes(file, NULL);
1634 				igt_assert_lt(0, crtc->n_planes);
1635 				crtc->planes = calloc(crtc->n_planes, sizeof(*crtc->planes));
1636 				igt_assert_f(crtc->planes, "Failed to allocate memory for %d planes\n", crtc->n_planes);
1637 
1638 				fseek(file, n, SEEK_SET);
1639 				parse_planes(file, crtc->planes);
1640 
1641 				if (crtc->pipe != pipe) {
1642 					free(crtc->planes);
1643 				} else {
1644 					ncrtc++;
1645 					break;
1646 				}
1647 			}
1648 		}
1649 
1650 		line++;
1651 	}
1652 
1653 	fclose(file);
1654 	close(fd);
1655 
1656 	igt_assert(ncrtc == 1);
1657 }
1658 
1659 /**
1660  * igt_assert_plane_visible:
1661  * @fd: Opened file descriptor
1662  * @pipe: Display pipe
1663  * @visibility: Boolean parameter to test against the plane's current visibility state
1664  *
1665  * Asserts only if the plane's visibility state matches the status being passed by @visibility
1666  */
igt_assert_plane_visible(int fd,enum pipe pipe,int plane_index,bool visibility)1667 void igt_assert_plane_visible(int fd, enum pipe pipe, int plane_index, bool visibility)
1668 {
1669 	struct kmstest_crtc crtc;
1670 	bool visible = true;
1671 
1672 	kmstest_get_crtc(fd, pipe, &crtc);
1673 
1674 	igt_assert(plane_index < crtc.n_planes);
1675 
1676 	if (crtc.planes[plane_index].pos_x > crtc.width ||
1677 	    crtc.planes[plane_index].pos_y > crtc.height)
1678 		visible = false;
1679 
1680 	free(crtc.planes);
1681 	igt_assert_eq(visible, visibility);
1682 }
1683 
1684 /**
1685  * kms_has_vblank:
1686  * @fd: DRM fd
1687  *
1688  * Get the VBlank errno after an attempt to call drmWaitVBlank(). This
1689  * function is useful for checking if a driver has support or not for VBlank.
1690  *
1691  * Returns: true if target driver has VBlank support, otherwise return false.
1692  */
kms_has_vblank(int fd)1693 bool kms_has_vblank(int fd)
1694 {
1695 	drmVBlank dummy_vbl;
1696 
1697 	memset(&dummy_vbl, 0, sizeof(drmVBlank));
1698 	dummy_vbl.request.type = DRM_VBLANK_RELATIVE;
1699 
1700 	errno = 0;
1701 	drmWaitVBlank(fd, &dummy_vbl);
1702 	return (errno != EOPNOTSUPP);
1703 }
1704 
1705 /*
1706  * A small modeset API
1707  */
1708 
1709 #define LOG_SPACES		"    "
1710 #define LOG_N_SPACES		(sizeof(LOG_SPACES) - 1)
1711 
1712 #define LOG_INDENT(d, section)				\
1713 	do {						\
1714 		igt_display_log(d, "%s {\n", section);	\
1715 		igt_display_log_shift(d, 1);		\
1716 	} while (0)
1717 #define LOG_UNINDENT(d)					\
1718 	do {						\
1719 		igt_display_log_shift(d, -1);		\
1720 		igt_display_log(d, "}\n");		\
1721 	} while (0)
1722 #define LOG(d, fmt, ...)	igt_display_log(d, fmt, ## __VA_ARGS__)
1723 
1724 static void  __attribute__((format(printf, 2, 3)))
igt_display_log(igt_display_t * display,const char * fmt,...)1725 igt_display_log(igt_display_t *display, const char *fmt, ...)
1726 {
1727 	va_list args;
1728 	int i;
1729 
1730 	va_start(args, fmt);
1731 	igt_debug("display: ");
1732 	for (i = 0; i < display->log_shift; i++)
1733 		igt_debug("%s", LOG_SPACES);
1734 	igt_vlog(IGT_LOG_DOMAIN, IGT_LOG_DEBUG, fmt, args);
1735 	va_end(args);
1736 }
1737 
igt_display_log_shift(igt_display_t * display,int shift)1738 static void igt_display_log_shift(igt_display_t *display, int shift)
1739 {
1740 	display->log_shift += shift;
1741 	igt_assert(display->log_shift >= 0);
1742 }
1743 
igt_output_refresh(igt_output_t * output)1744 static void igt_output_refresh(igt_output_t *output)
1745 {
1746 	igt_display_t *display = output->display;
1747 	unsigned long crtc_idx_mask = 0;
1748 
1749 	if (output->pending_pipe != PIPE_NONE)
1750 		crtc_idx_mask = 1 << output->pending_pipe;
1751 
1752 	kmstest_free_connector_config(&output->config);
1753 
1754 	_kmstest_connector_config(display->drm_fd, output->id, crtc_idx_mask,
1755 				  &output->config, output->force_reprobe);
1756 	output->force_reprobe = false;
1757 
1758 	if (!output->name && output->config.connector) {
1759 		drmModeConnector *c = output->config.connector;
1760 
1761 		igt_assert_neq(asprintf(&output->name, "%s-%d", kmstest_connector_type_str(c->connector_type), c->connector_type_id),
1762 			       -1);
1763 	}
1764 
1765 	if (output->config.connector)
1766 		igt_atomic_fill_connector_props(display, output,
1767 			IGT_NUM_CONNECTOR_PROPS, igt_connector_prop_names);
1768 
1769 	LOG(display, "%s: Selecting pipe %s\n", output->name,
1770 	    kmstest_pipe_name(output->pending_pipe));
1771 }
1772 
1773 static int
igt_plane_set_property(igt_plane_t * plane,uint32_t prop_id,uint64_t value)1774 igt_plane_set_property(igt_plane_t *plane, uint32_t prop_id, uint64_t value)
1775 {
1776 	igt_pipe_t *pipe = plane->pipe;
1777 	igt_display_t *display = pipe->display;
1778 
1779 	return drmModeObjectSetProperty(display->drm_fd, plane->drm_plane->plane_id,
1780 				 DRM_MODE_OBJECT_PLANE, prop_id, value);
1781 }
1782 
1783 /*
1784  * Walk a plane's property list to determine its type.  If we don't
1785  * find a type property, then the kernel doesn't support universal
1786  * planes and we know the plane is an overlay/sprite.
1787  */
get_drm_plane_type(int drm_fd,uint32_t plane_id)1788 static int get_drm_plane_type(int drm_fd, uint32_t plane_id)
1789 {
1790 	uint64_t value;
1791 	bool has_prop;
1792 
1793 	has_prop = kmstest_get_property(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE,
1794 					"type", NULL, &value, NULL);
1795 	if (has_prop)
1796 		return (int)value;
1797 
1798 	return DRM_PLANE_TYPE_OVERLAY;
1799 }
1800 
igt_plane_reset(igt_plane_t * plane)1801 static void igt_plane_reset(igt_plane_t *plane)
1802 {
1803 	/* Reset src coordinates. */
1804 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_X, 0);
1805 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_Y, 0);
1806 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_W, 0);
1807 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_H, 0);
1808 
1809 	/* Reset crtc coordinates. */
1810 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_X, 0);
1811 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_Y, 0);
1812 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_W, 0);
1813 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_H, 0);
1814 
1815 	/* Reset binding to fb and crtc. */
1816 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, 0);
1817 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, 0);
1818 
1819 	if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
1820 		igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
1821 			igt_color_encoding_to_str(IGT_COLOR_YCBCR_BT601));
1822 
1823 	if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
1824 		igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
1825 			igt_color_range_to_str(IGT_COLOR_YCBCR_LIMITED_RANGE));
1826 
1827 	/* Use default rotation */
1828 	if (igt_plane_has_prop(plane, IGT_PLANE_ROTATION))
1829 		igt_plane_set_prop_value(plane, IGT_PLANE_ROTATION, IGT_ROTATION_0);
1830 
1831 	if (igt_plane_has_prop(plane, IGT_PLANE_PIXEL_BLEND_MODE))
1832 		igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Pre-multiplied");
1833 
1834 	if (igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
1835 	{
1836 		uint64_t max_alpha = 0xffff;
1837 		drmModePropertyPtr alpha_prop = drmModeGetProperty(
1838 			plane->pipe->display->drm_fd,
1839 			plane->props[IGT_PLANE_ALPHA]);
1840 
1841 		if (alpha_prop)
1842 		{
1843 			if (alpha_prop->flags & DRM_MODE_PROP_RANGE)
1844 			{
1845 				max_alpha = alpha_prop->values[1];
1846 			}
1847 
1848 			drmModeFreeProperty(alpha_prop);
1849 		}
1850 
1851 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, max_alpha);
1852 	}
1853 
1854 
1855 	igt_plane_clear_prop_changed(plane, IGT_PLANE_IN_FENCE_FD);
1856 	plane->values[IGT_PLANE_IN_FENCE_FD] = ~0ULL;
1857 	plane->gem_handle = 0;
1858 }
1859 
igt_pipe_reset(igt_pipe_t * pipe)1860 static void igt_pipe_reset(igt_pipe_t *pipe)
1861 {
1862 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, 0);
1863 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_ACTIVE, 0);
1864 	igt_pipe_obj_clear_prop_changed(pipe, IGT_CRTC_OUT_FENCE_PTR);
1865 
1866 	if (igt_pipe_obj_has_prop(pipe, IGT_CRTC_CTM))
1867 		igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_CTM, 0);
1868 
1869 	if (igt_pipe_obj_has_prop(pipe, IGT_CRTC_GAMMA_LUT))
1870 		igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_GAMMA_LUT, 0);
1871 
1872 	if (igt_pipe_obj_has_prop(pipe, IGT_CRTC_DEGAMMA_LUT))
1873 		igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_DEGAMMA_LUT, 0);
1874 
1875 	pipe->out_fence_fd = -1;
1876 }
1877 
igt_output_reset(igt_output_t * output)1878 static void igt_output_reset(igt_output_t *output)
1879 {
1880 	output->pending_pipe = PIPE_NONE;
1881 	output->use_override_mode = false;
1882 	memset(&output->override_mode, 0, sizeof(output->override_mode));
1883 
1884 	igt_output_set_prop_value(output, IGT_CONNECTOR_CRTC_ID, 0);
1885 
1886 	if (igt_output_has_prop(output, IGT_CONNECTOR_BROADCAST_RGB))
1887 		igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB,
1888 					  BROADCAST_RGB_FULL);
1889 
1890 	if (igt_output_has_prop(output, IGT_CONNECTOR_CONTENT_PROTECTION))
1891 		igt_output_set_prop_enum(output, IGT_CONNECTOR_CONTENT_PROTECTION,
1892 					 "Undesired");
1893 }
1894 
1895 /**
1896  * igt_display_reset:
1897  * @display: a pointer to an #igt_display_t structure
1898  *
1899  * Reset basic pipes, connectors and planes on @display back to default values.
1900  * In particular, the following properties will be reset:
1901  *
1902  * For outputs:
1903  * - %IGT_CONNECTOR_CRTC_ID
1904  * - %IGT_CONNECTOR_BROADCAST_RGB (if applicable)
1905  *   %IGT_CONNECTOR_CONTENT_PROTECTION (if applicable)
1906  * - igt_output_override_mode() to default.
1907  *
1908  * For pipes:
1909  * - %IGT_CRTC_MODE_ID (leaked)
1910  * - %IGT_CRTC_ACTIVE
1911  * - %IGT_CRTC_OUT_FENCE_PTR
1912  *
1913  * For planes:
1914  * - %IGT_PLANE_SRC_*
1915  * - %IGT_PLANE_CRTC_*
1916  * - %IGT_PLANE_FB_ID
1917  * - %IGT_PLANE_CRTC_ID
1918  * - %IGT_PLANE_ROTATION
1919  * - %IGT_PLANE_IN_FENCE_FD
1920  */
igt_display_reset(igt_display_t * display)1921 void igt_display_reset(igt_display_t *display)
1922 {
1923 	enum pipe pipe;
1924 	int i;
1925 
1926 	/*
1927 	 * Allow resetting rotation on all planes, which is normally
1928 	 * prohibited on the primary and cursor plane for legacy commits.
1929 	 */
1930 	display->first_commit = true;
1931 
1932 	for_each_pipe(display, pipe) {
1933 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
1934 		igt_plane_t *plane;
1935 
1936 		for_each_plane_on_pipe(display, pipe, plane)
1937 			igt_plane_reset(plane);
1938 
1939 		igt_pipe_reset(pipe_obj);
1940 	}
1941 
1942 	for (i = 0; i < display->n_outputs; i++) {
1943 		igt_output_t *output = &display->outputs[i];
1944 
1945 		igt_output_reset(output);
1946 	}
1947 }
1948 
1949 static void igt_fill_plane_format_mod(igt_display_t *display, igt_plane_t *plane);
1950 static void igt_fill_display_format_mod(igt_display_t *display);
1951 
1952 /**
1953  * igt_display_require:
1954  * @display: a pointer to an #igt_display_t structure
1955  * @drm_fd: a drm file descriptor
1956  *
1957  * Initialize @display and allocate the various resources required. Use
1958  * #igt_display_fini to release the resources when they are no longer required.
1959  *
1960  * This function automatically skips if the kernel driver doesn't support any
1961  * CRTC or outputs.
1962  */
igt_display_require(igt_display_t * display,int drm_fd)1963 void igt_display_require(igt_display_t *display, int drm_fd)
1964 {
1965 	drmModeRes *resources;
1966 	drmModePlaneRes *plane_resources;
1967 	int i;
1968 
1969 	memset(display, 0, sizeof(igt_display_t));
1970 
1971 	LOG_INDENT(display, "init");
1972 
1973 	display->drm_fd = drm_fd;
1974 
1975 	resources = drmModeGetResources(display->drm_fd);
1976 	if (!resources)
1977 		goto out;
1978 
1979 	/*
1980 	 * We cache the number of pipes, that number is a physical limit of the
1981 	 * hardware and cannot change of time (for now, at least).
1982 	 */
1983 	display->n_pipes = resources->count_crtcs;
1984 	display->pipes = calloc(sizeof(igt_pipe_t), display->n_pipes);
1985 	igt_assert_f(display->pipes, "Failed to allocate memory for %d pipes\n", display->n_pipes);
1986 
1987 	drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1988 	if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) == 0)
1989 		display->is_atomic = 1;
1990 
1991 	plane_resources = drmModeGetPlaneResources(display->drm_fd);
1992 	igt_assert(plane_resources);
1993 
1994 	display->n_planes = plane_resources->count_planes;
1995 	display->planes = calloc(sizeof(igt_plane_t), display->n_planes);
1996 	igt_assert_f(display->planes, "Failed to allocate memory for %d planes\n", display->n_planes);
1997 
1998 	for (i = 0; i < plane_resources->count_planes; ++i) {
1999 		igt_plane_t *plane = &display->planes[i];
2000 		uint32_t id = plane_resources->planes[i];
2001 
2002 		plane->drm_plane = drmModeGetPlane(display->drm_fd, id);
2003 		igt_assert(plane->drm_plane);
2004 
2005 		plane->type = get_drm_plane_type(display->drm_fd, id);
2006 
2007 		/*
2008 		 * TODO: Fill in the rest of the plane properties here and
2009 		 * move away from the plane per pipe model to align closer
2010 		 * to the DRM KMS model.
2011 		 */
2012 	}
2013 
2014 	for_each_pipe(display, i) {
2015 		igt_pipe_t *pipe = &display->pipes[i];
2016 		igt_plane_t *plane;
2017 		int p = 1;
2018 		int j, type;
2019 		uint8_t last_plane = 0, n_planes = 0;
2020 
2021 		pipe->crtc_id = resources->crtcs[i];
2022 		pipe->display = display;
2023 		pipe->pipe = i;
2024 		pipe->plane_cursor = -1;
2025 		pipe->plane_primary = -1;
2026 		pipe->planes = NULL;
2027 
2028 		igt_fill_pipe_props(display, pipe, IGT_NUM_CRTC_PROPS, igt_crtc_prop_names);
2029 
2030 		/* count number of valid planes */
2031 		for (j = 0; j < display->n_planes; j++) {
2032 			drmModePlane *drm_plane = display->planes[j].drm_plane;
2033 			igt_assert(drm_plane);
2034 
2035 			if (drm_plane->possible_crtcs & (1 << i))
2036 				n_planes++;
2037 		}
2038 
2039 		igt_assert_lt(0, n_planes);
2040 		pipe->planes = calloc(sizeof(igt_plane_t), n_planes);
2041 		igt_assert_f(pipe->planes, "Failed to allocate memory for %d planes\n", n_planes);
2042 		last_plane = n_planes - 1;
2043 
2044 		/* add the planes that can be used with that pipe */
2045 		for (j = 0; j < display->n_planes; j++) {
2046 			igt_plane_t *global_plane = &display->planes[j];
2047 			drmModePlane *drm_plane = global_plane->drm_plane;
2048 
2049 			if (!(drm_plane->possible_crtcs & (1 << i)))
2050 				continue;
2051 
2052 			type = global_plane->type;
2053 
2054 			if (type == DRM_PLANE_TYPE_PRIMARY && pipe->plane_primary == -1) {
2055 				plane = &pipe->planes[0];
2056 				plane->index = 0;
2057 				pipe->plane_primary = 0;
2058 			} else if (type == DRM_PLANE_TYPE_CURSOR && pipe->plane_cursor == -1) {
2059 				plane = &pipe->planes[last_plane];
2060 				plane->index = last_plane;
2061 				pipe->plane_cursor = last_plane;
2062 				display->has_cursor_plane = true;
2063 			} else {
2064 				plane = &pipe->planes[p];
2065 				plane->index = p++;
2066 			}
2067 
2068 			igt_assert_f(plane->index < n_planes, "n_planes < plane->index failed\n");
2069 			plane->type = type;
2070 			plane->pipe = pipe;
2071 			plane->drm_plane = drm_plane;
2072 			plane->values[IGT_PLANE_IN_FENCE_FD] = ~0ULL;
2073 			plane->ref = global_plane;
2074 
2075 			/*
2076 			 * HACK: point the global plane to the first pipe that
2077 			 * it can go on.
2078 			 */
2079 			if (!global_plane->ref)
2080 				igt_plane_set_pipe(plane, pipe);
2081 
2082 			igt_fill_plane_props(display, plane, IGT_NUM_PLANE_PROPS, igt_plane_prop_names);
2083 
2084 			igt_fill_plane_format_mod(display, plane);
2085 		}
2086 
2087 		/*
2088 		 * At the bare minimum, we should expect to have a primary
2089 		 * plane, and it must be in slot 0.
2090 		 */
2091 		igt_assert_eq(pipe->plane_primary, 0);
2092 
2093 		/* Check that we filled every slot exactly once */
2094 		if (display->has_cursor_plane)
2095 			igt_assert_eq(p, last_plane);
2096 		else
2097 			igt_assert_eq(p, n_planes);
2098 
2099 		pipe->n_planes = n_planes;
2100 	}
2101 
2102 	igt_fill_display_format_mod(display);
2103 
2104 	/*
2105 	 * The number of connectors is set, so we just initialize the outputs
2106 	 * array in _init(). This may change when we need dynamic connectors
2107 	 * (say DisplayPort MST).
2108 	 */
2109 	display->n_outputs = resources->count_connectors;
2110 	display->outputs = calloc(display->n_outputs, sizeof(igt_output_t));
2111 	igt_assert_f(display->outputs, "Failed to allocate memory for %d outputs\n", display->n_outputs);
2112 
2113 	for (i = 0; i < display->n_outputs; i++) {
2114 		igt_output_t *output = &display->outputs[i];
2115 		drmModeConnector *connector;
2116 
2117 		/*
2118 		 * We don't assign each output a pipe unless
2119 		 * a pipe is set with igt_output_set_pipe().
2120 		 */
2121 		output->pending_pipe = PIPE_NONE;
2122 		output->id = resources->connectors[i];
2123 		output->display = display;
2124 
2125 		igt_output_refresh(output);
2126 
2127 		connector = output->config.connector;
2128 		if (connector && (!connector->count_modes ||
2129 		    connector->connection == DRM_MODE_UNKNOWNCONNECTION)) {
2130 			output->force_reprobe = true;
2131 			igt_output_refresh(output);
2132 		}
2133 	}
2134 
2135 	drmModeFreePlaneResources(plane_resources);
2136 	drmModeFreeResources(resources);
2137 
2138 	/* Set reasonable default values for every object in the display. */
2139 	igt_display_reset(display);
2140 
2141 out:
2142 	LOG_UNINDENT(display);
2143 
2144 	if (display->n_pipes && display->n_outputs)
2145 		igt_enable_connectors(drm_fd);
2146 	else
2147 		igt_skip("No KMS driver or no outputs, pipes: %d, outputs: %d\n",
2148 			 display->n_pipes, display->n_outputs);
2149 }
2150 
2151 /**
2152  * igt_display_get_n_pipes:
2153  * @display: A pointer to an #igt_display_t structure
2154  *
2155  * Returns total number of pipes for the given @display
2156  */
igt_display_get_n_pipes(igt_display_t * display)2157 int igt_display_get_n_pipes(igt_display_t *display)
2158 {
2159 	return display->n_pipes;
2160 }
2161 
2162 /**
2163  * igt_display_require_output:
2164  * @display: A pointer to an #igt_display_t structure
2165  *
2166  * Checks whether there's a valid @pipe/@output combination for the given @display
2167  * Skips test if a valid combination of @pipe and @output is not found
2168  */
igt_display_require_output(igt_display_t * display)2169 void igt_display_require_output(igt_display_t *display)
2170 {
2171 	enum pipe pipe;
2172 	igt_output_t *output;
2173 
2174 	for_each_pipe_with_valid_output(display, pipe, output)
2175 		return;
2176 
2177 	igt_skip("No valid crtc/connector combinations found.\n");
2178 }
2179 
2180 /**
2181  * igt_display_require_output_on_pipe:
2182  * @display: A pointer to an #igt_display_t structure
2183  * @pipe: Display pipe
2184  *
2185  * Checks whether there's a valid @pipe/@output combination for the given @display and @pipe
2186  * Skips test if a valid @pipe is not found
2187  */
igt_display_require_output_on_pipe(igt_display_t * display,enum pipe pipe)2188 void igt_display_require_output_on_pipe(igt_display_t *display, enum pipe pipe)
2189 {
2190 	igt_output_t *output;
2191 
2192 	igt_skip_on_f(pipe >= igt_display_get_n_pipes(display),
2193 		      "Pipe %s does not exist.\n", kmstest_pipe_name(pipe));
2194 
2195 	for_each_valid_output_on_pipe(display, pipe, output)
2196 		return;
2197 
2198 	igt_skip("No valid connector found on pipe %s\n", kmstest_pipe_name(pipe));
2199 }
2200 
2201 /**
2202  * igt_output_from_connector:
2203  * @display: a pointer to an #igt_display_t structure
2204  * @connector: a pointer to a drmModeConnector
2205  *
2206  * Finds the output corresponding to the given connector
2207  *
2208  * Returns: A #igt_output_t structure configured to use the connector, or NULL
2209  * if none was found
2210  */
igt_output_from_connector(igt_display_t * display,drmModeConnector * connector)2211 igt_output_t *igt_output_from_connector(igt_display_t *display,
2212 					drmModeConnector *connector)
2213 {
2214 	igt_output_t *output, *found = NULL;
2215 	int i;
2216 
2217 	for (i = 0; i < display->n_outputs; i++) {
2218 		output = &display->outputs[i];
2219 
2220 		if (output->config.connector &&
2221 		    output->config.connector->connector_id ==
2222 		    connector->connector_id) {
2223 			found = output;
2224 			break;
2225 		}
2226 	}
2227 
2228 	return found;
2229 }
2230 
igt_std_1024_mode_get(void)2231 const drmModeModeInfo *igt_std_1024_mode_get(void)
2232 {
2233 	static const drmModeModeInfo std_1024_mode = {
2234 		.clock = 65000,
2235 		.hdisplay = 1024,
2236 		.hsync_start = 1048,
2237 		.hsync_end = 1184,
2238 		.htotal = 1344,
2239 		.hskew = 0,
2240 		.vdisplay = 768,
2241 		.vsync_start = 771,
2242 		.vsync_end = 777,
2243 		.vtotal = 806,
2244 		.vscan = 0,
2245 		.vrefresh = 60,
2246 		.flags = 0xA,
2247 		.type = 0x40,
2248 		.name = "Custom 1024x768",
2249 	};
2250 
2251 	return &std_1024_mode;
2252 }
2253 
igt_pipe_fini(igt_pipe_t * pipe)2254 static void igt_pipe_fini(igt_pipe_t *pipe)
2255 {
2256 	free(pipe->planes);
2257 	pipe->planes = NULL;
2258 
2259 	if (pipe->out_fence_fd != -1)
2260 		close(pipe->out_fence_fd);
2261 }
2262 
igt_output_fini(igt_output_t * output)2263 static void igt_output_fini(igt_output_t *output)
2264 {
2265 	kmstest_free_connector_config(&output->config);
2266 	free(output->name);
2267 	output->name = NULL;
2268 }
2269 
2270 /**
2271  * igt_display_fini:
2272  * @display: a pointer to an #igt_display_t structure
2273  *
2274  * Release any resources associated with @display. This does not free @display
2275  * itself.
2276  */
igt_display_fini(igt_display_t * display)2277 void igt_display_fini(igt_display_t *display)
2278 {
2279 	int i;
2280 
2281 	for (i = 0; i < display->n_planes; ++i) {
2282 		igt_plane_t *plane = &display->planes[i];
2283 
2284 		if (plane->drm_plane) {
2285 			drmModeFreePlane(plane->drm_plane);
2286 			plane->drm_plane = NULL;
2287 		}
2288 	}
2289 
2290 	for (i = 0; i < display->n_pipes; i++)
2291 		igt_pipe_fini(&display->pipes[i]);
2292 
2293 	for (i = 0; i < display->n_outputs; i++)
2294 		igt_output_fini(&display->outputs[i]);
2295 	free(display->outputs);
2296 	display->outputs = NULL;
2297 	free(display->pipes);
2298 	display->pipes = NULL;
2299 	free(display->planes);
2300 	display->planes = NULL;
2301 }
2302 
igt_display_refresh(igt_display_t * display)2303 static void igt_display_refresh(igt_display_t *display)
2304 {
2305 	igt_output_t *output;
2306 	int i;
2307 
2308 	unsigned long pipes_in_use = 0;
2309 
2310        /* Check that two outputs aren't trying to use the same pipe */
2311 	for (i = 0; i < display->n_outputs; i++) {
2312 		output = &display->outputs[i];
2313 
2314 		if (output->pending_pipe != PIPE_NONE) {
2315 			if (pipes_in_use & (1 << output->pending_pipe))
2316 				goto report_dup;
2317 
2318 			pipes_in_use |= 1 << output->pending_pipe;
2319 		}
2320 
2321 		if (output->force_reprobe)
2322 			igt_output_refresh(output);
2323 	}
2324 
2325 	return;
2326 
2327 report_dup:
2328 	for (; i > 0; i--) {
2329 		igt_output_t *b = &display->outputs[i - 1];
2330 
2331 		igt_assert_f(output->pending_pipe !=
2332 			     b->pending_pipe,
2333 			     "%s and %s are both trying to use pipe %s\n",
2334 			     igt_output_name(output), igt_output_name(b),
2335 			     kmstest_pipe_name(output->pending_pipe));
2336 	}
2337 }
2338 
igt_output_get_driving_pipe(igt_output_t * output)2339 static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
2340 {
2341 	igt_display_t *display = output->display;
2342 	enum pipe pipe;
2343 
2344 	if (output->pending_pipe == PIPE_NONE) {
2345 		/*
2346 		 * The user hasn't specified a pipe to use, return none.
2347 		 */
2348 		return NULL;
2349 	} else {
2350 		/*
2351 		 * Otherwise, return the pending pipe (ie the pipe that should
2352 		 * drive this output after the commit()
2353 		 */
2354 		pipe = output->pending_pipe;
2355 	}
2356 
2357 	igt_assert(pipe >= 0 && pipe < display->n_pipes);
2358 
2359 	return &display->pipes[pipe];
2360 }
2361 
igt_pipe_get_plane(igt_pipe_t * pipe,int plane_idx)2362 static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int plane_idx)
2363 {
2364 	igt_require_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2365 		      "Valid pipe->planes plane_idx not found, plane_idx=%d n_planes=%d",
2366 		      plane_idx, pipe->n_planes);
2367 
2368 	return &pipe->planes[plane_idx];
2369 }
2370 
2371 /**
2372  * igt_pipe_get_plane_type:
2373  * @pipe: Target pipe
2374  * @plane_type: Cursor, primary or an overlay plane
2375  *
2376  * Finds a valid plane type for the given @pipe otherwise
2377  * it skips the test if the right combination of @pipe/@plane_type is not found
2378  *
2379  * Returns: A #igt_plane_t structure that matches the requested plane type
2380  */
igt_pipe_get_plane_type(igt_pipe_t * pipe,int plane_type)2381 igt_plane_t *igt_pipe_get_plane_type(igt_pipe_t *pipe, int plane_type)
2382 {
2383 	int i, plane_idx = -1;
2384 
2385 	switch(plane_type) {
2386 	case DRM_PLANE_TYPE_CURSOR:
2387 		plane_idx = pipe->plane_cursor;
2388 		break;
2389 	case DRM_PLANE_TYPE_PRIMARY:
2390 		plane_idx = pipe->plane_primary;
2391 		break;
2392 	case DRM_PLANE_TYPE_OVERLAY:
2393 		for(i = 0; i < pipe->n_planes; i++)
2394 			if (pipe->planes[i].type == DRM_PLANE_TYPE_OVERLAY)
2395 			    plane_idx = i;
2396 		break;
2397 	default:
2398 		break;
2399 	}
2400 
2401 	igt_require_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2402 		      "Valid pipe->planes idx not found. plane_idx=%d plane_type=%d n_planes=%d\n",
2403 		      plane_idx, plane_type, pipe->n_planes);
2404 
2405 	return &pipe->planes[plane_idx];
2406 }
2407 
2408 /**
2409  * igt_pipe_count_plane_type:
2410  * @pipe: Target pipe
2411  * @plane_type: Cursor, primary or an overlay plane
2412  *
2413  * Counts the number of planes of type @plane_type for the provided @pipe.
2414  *
2415  * Returns: The number of planes that match the requested plane type
2416  */
igt_pipe_count_plane_type(igt_pipe_t * pipe,int plane_type)2417 int igt_pipe_count_plane_type(igt_pipe_t *pipe, int plane_type)
2418 {
2419 	int i, count = 0;
2420 
2421 	for(i = 0; i < pipe->n_planes; i++)
2422 		if (pipe->planes[i].type == plane_type)
2423 			count++;
2424 
2425 	return count;
2426 }
2427 
2428 /**
2429  * igt_pipe_get_plane_type_index:
2430  * @pipe: Target pipe
2431  * @plane_type: Cursor, primary or an overlay plane
2432  * @index: the index of the plane among planes of the same type
2433  *
2434  * Get the @index th plane of type @plane_type for the provided @pipe.
2435  *
2436  * Returns: The @index th plane that matches the requested plane type
2437  */
igt_pipe_get_plane_type_index(igt_pipe_t * pipe,int plane_type,int index)2438 igt_plane_t *igt_pipe_get_plane_type_index(igt_pipe_t *pipe, int plane_type,
2439 					   int index)
2440 {
2441 	int i, type_index = 0;
2442 
2443 	for(i = 0; i < pipe->n_planes; i++) {
2444 		if (pipe->planes[i].type != plane_type)
2445 			continue;
2446 
2447 		if (type_index == index)
2448 			return &pipe->planes[i];
2449 
2450 		type_index++;
2451 	}
2452 
2453 	return NULL;
2454 }
2455 
output_is_internal_panel(igt_output_t * output)2456 static bool output_is_internal_panel(igt_output_t *output)
2457 {
2458 	switch (output->config.connector->connector_type) {
2459 	case DRM_MODE_CONNECTOR_LVDS:
2460 	case DRM_MODE_CONNECTOR_eDP:
2461 	case DRM_MODE_CONNECTOR_DSI:
2462 	case DRM_MODE_CONNECTOR_DPI:
2463 		return true;
2464 	default:
2465 		return false;
2466 	}
2467 }
2468 
__igt_pipe_populate_outputs(igt_display_t * display,igt_output_t ** chosen_outputs)2469 igt_output_t **__igt_pipe_populate_outputs(igt_display_t *display, igt_output_t **chosen_outputs)
2470 {
2471 	unsigned full_pipe_mask = (1 << (display->n_pipes)) - 1, assigned_pipes = 0;
2472 	igt_output_t *output;
2473 	int i, j;
2474 
2475 	memset(chosen_outputs, 0, sizeof(*chosen_outputs) * display->n_pipes);
2476 
2477 	/*
2478 	 * Try to assign all outputs to the first available CRTC for
2479 	 * it, start with the outputs restricted to 1 pipe, then increase
2480 	 * number of pipes until we assign connectors to all pipes.
2481 	 */
2482 	for (i = 0; i <= display->n_pipes; i++) {
2483 		for_each_connected_output(display, output) {
2484 			uint32_t pipe_mask = output->config.valid_crtc_idx_mask & full_pipe_mask;
2485 			bool found = false;
2486 
2487 			if (output_is_internal_panel(output)) {
2488 				/*
2489 				 * Internal panel should be assigned to pipe A
2490 				 * if possible, so make sure they're enumerated
2491 				 * first.
2492 				 */
2493 
2494 				if (i)
2495 					continue;
2496 			} else if (__builtin_popcount(pipe_mask) != i)
2497 				continue;
2498 
2499 			for (j = 0; j < display->n_pipes; j++) {
2500 				bool pipe_assigned = assigned_pipes & (1 << j);
2501 
2502 				if (pipe_assigned || !(pipe_mask & (1 << j)))
2503 					continue;
2504 
2505 				if (!found) {
2506 					/* We found an unassigned pipe, use it! */
2507 					found = true;
2508 					assigned_pipes |= 1 << j;
2509 					chosen_outputs[j] = output;
2510 				} else if (!chosen_outputs[j] ||
2511 					   /*
2512 					    * Overwrite internal panel if not assigned,
2513 					    * external outputs are faster to do modesets
2514 					    */
2515 					   output_is_internal_panel(chosen_outputs[j]))
2516 					chosen_outputs[j] = output;
2517 			}
2518 
2519 			if (!found)
2520 				igt_warn("Output %s could not be assigned to a pipe\n",
2521 					 igt_output_name(output));
2522 		}
2523 	}
2524 
2525 	return chosen_outputs;
2526 }
2527 
2528 /**
2529  * igt_get_single_output_for_pipe:
2530  * @display: a pointer to an #igt_display_t structure
2531  * @pipe: The pipe for which an #igt_output_t must be returned.
2532  *
2533  * Get a compatible output for a pipe.
2534  *
2535  * Returns: A compatible output for a given pipe, or NULL.
2536  */
igt_get_single_output_for_pipe(igt_display_t * display,enum pipe pipe)2537 igt_output_t *igt_get_single_output_for_pipe(igt_display_t *display, enum pipe pipe)
2538 {
2539 	igt_output_t *chosen_outputs[display->n_pipes];
2540 
2541 	igt_assert(pipe != PIPE_NONE);
2542 	igt_require(pipe < display->n_pipes);
2543 
2544 	__igt_pipe_populate_outputs(display, chosen_outputs);
2545 
2546 	return chosen_outputs[pipe];
2547 }
2548 
igt_pipe_get_output(igt_pipe_t * pipe)2549 static igt_output_t *igt_pipe_get_output(igt_pipe_t *pipe)
2550 {
2551 	igt_display_t *display = pipe->display;
2552 	int i;
2553 
2554 	for (i = 0; i < display->n_outputs; i++) {
2555 		igt_output_t *output = &display->outputs[i];
2556 
2557 		if (output->pending_pipe == pipe->pipe)
2558 			return output;
2559 	}
2560 
2561 	return NULL;
2562 }
2563 
igt_plane_get_fb_id(igt_plane_t * plane)2564 static uint32_t igt_plane_get_fb_id(igt_plane_t *plane)
2565 {
2566 	return plane->values[IGT_PLANE_FB_ID];
2567 }
2568 
2569 #define CHECK_RETURN(r, fail) {	\
2570 	if (r && !fail)		\
2571 		return r;	\
2572 	igt_assert_eq(r, 0);	\
2573 }
2574 
2575 /*
2576  * Add position and fb changes of a plane to the atomic property set
2577  */
2578 static void
igt_atomic_prepare_plane_commit(igt_plane_t * plane,igt_pipe_t * pipe,drmModeAtomicReq * req)2579 igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
2580 	drmModeAtomicReq *req)
2581 {
2582 	igt_display_t *display = pipe->display;
2583 	int i;
2584 
2585 	igt_assert(plane->drm_plane);
2586 
2587 	LOG(display,
2588 	    "populating plane data: %s.%d, fb %u\n",
2589 	    kmstest_pipe_name(pipe->pipe),
2590 	    plane->index,
2591 	    igt_plane_get_fb_id(plane));
2592 
2593 	for (i = 0; i < IGT_NUM_PLANE_PROPS; i++) {
2594 		if (!igt_plane_is_prop_changed(plane, i))
2595 			continue;
2596 
2597 		/* it's an error to try an unsupported feature */
2598 		igt_assert(plane->props[i]);
2599 
2600 		igt_debug("plane %s.%d: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
2601 			kmstest_pipe_name(pipe->pipe), plane->index, igt_plane_prop_names[i],
2602 			plane->values[i], plane->values[i]);
2603 
2604 		igt_assert_lt(0, drmModeAtomicAddProperty(req, plane->drm_plane->plane_id,
2605 						  plane->props[i],
2606 						  plane->values[i]));
2607 	}
2608 }
2609 
2610 /*
2611  * Properties that can be changed through legacy SetProperty:
2612  * - Obviously not the XYWH SRC/CRTC coordinates.
2613  * - Not CRTC_ID or FENCE_ID, done through SetPlane.
2614  * - Can't set IN_FENCE_FD, that would be silly.
2615  *
2616  * Theoretically the above can all be set through the legacy path
2617  * with the atomic cap set, but that's not how our legacy plane
2618  * commit behaves, so blacklist it by default.
2619  */
2620 #define LEGACY_PLANE_COMMIT_MASK \
2621 	(((1ULL << IGT_NUM_PLANE_PROPS) - 1) & \
2622 	 ~(IGT_PLANE_COORD_CHANGED_MASK | \
2623 	   (1ULL << IGT_PLANE_FB_ID) | \
2624 	   (1ULL << IGT_PLANE_CRTC_ID) | \
2625 	   (1ULL << IGT_PLANE_IN_FENCE_FD)))
2626 
2627 /*
2628  * Commit position and fb changes to a DRM plane via the SetPlane ioctl; if the
2629  * DRM call to program the plane fails, we'll either fail immediately (for
2630  * tests that expect the commit to succeed) or return the failure code (for
2631  * tests that expect a specific error code).
2632  */
igt_drm_plane_commit(igt_plane_t * plane,igt_pipe_t * pipe,bool fail_on_error)2633 static int igt_drm_plane_commit(igt_plane_t *plane,
2634 				igt_pipe_t *pipe,
2635 				bool fail_on_error)
2636 {
2637 	igt_display_t *display = pipe->display;
2638 	uint32_t fb_id, crtc_id;
2639 	int ret, i;
2640 	uint32_t src_x;
2641 	uint32_t src_y;
2642 	uint32_t src_w;
2643 	uint32_t src_h;
2644 	int32_t crtc_x;
2645 	int32_t crtc_y;
2646 	uint32_t crtc_w;
2647 	uint32_t crtc_h;
2648 	uint64_t changed_mask;
2649 	bool setplane =
2650 		igt_plane_is_prop_changed(plane, IGT_PLANE_FB_ID) ||
2651 		plane->changed & IGT_PLANE_COORD_CHANGED_MASK;
2652 
2653 	igt_assert(plane->drm_plane);
2654 
2655 	fb_id = igt_plane_get_fb_id(plane);
2656 	crtc_id = pipe->crtc_id;
2657 
2658 	if (setplane && fb_id == 0) {
2659 		LOG(display,
2660 		    "SetPlane pipe %s, plane %d, disabling\n",
2661 		    kmstest_pipe_name(pipe->pipe),
2662 		    plane->index);
2663 
2664 		ret = drmModeSetPlane(display->drm_fd,
2665 				      plane->drm_plane->plane_id,
2666 				      crtc_id,
2667 				      fb_id,
2668 				      0,    /* flags */
2669 				      0, 0, /* crtc_x, crtc_y */
2670 				      0, 0, /* crtc_w, crtc_h */
2671 				      IGT_FIXED(0,0), /* src_x */
2672 				      IGT_FIXED(0,0), /* src_y */
2673 				      IGT_FIXED(0,0), /* src_w */
2674 				      IGT_FIXED(0,0) /* src_h */);
2675 
2676 		CHECK_RETURN(ret, fail_on_error);
2677 	} else if (setplane) {
2678 		src_x = plane->values[IGT_PLANE_SRC_X];
2679 		src_y = plane->values[IGT_PLANE_SRC_Y];
2680 		src_w = plane->values[IGT_PLANE_SRC_W];
2681 		src_h = plane->values[IGT_PLANE_SRC_H];
2682 		crtc_x = plane->values[IGT_PLANE_CRTC_X];
2683 		crtc_y = plane->values[IGT_PLANE_CRTC_Y];
2684 		crtc_w = plane->values[IGT_PLANE_CRTC_W];
2685 		crtc_h = plane->values[IGT_PLANE_CRTC_H];
2686 
2687 		LOG(display,
2688 		    "SetPlane %s.%d, fb %u, src = (%d, %d) "
2689 			"%ux%u dst = (%u, %u) %ux%u\n",
2690 		    kmstest_pipe_name(pipe->pipe),
2691 		    plane->index,
2692 		    fb_id,
2693 		    src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
2694 		    crtc_x, crtc_y, crtc_w, crtc_h);
2695 
2696 		ret = drmModeSetPlane(display->drm_fd,
2697 				      plane->drm_plane->plane_id,
2698 				      crtc_id,
2699 				      fb_id,
2700 				      0,    /* flags */
2701 				      crtc_x, crtc_y,
2702 				      crtc_w, crtc_h,
2703 				      src_x, src_y,
2704 				      src_w, src_h);
2705 
2706 		CHECK_RETURN(ret, fail_on_error);
2707 	}
2708 
2709 	changed_mask = plane->changed & LEGACY_PLANE_COMMIT_MASK;
2710 
2711 	for (i = 0; i < IGT_NUM_PLANE_PROPS; i++) {
2712 		if (!(changed_mask & (1 << i)))
2713 			continue;
2714 
2715 		LOG(display, "SetProp plane %s.%d \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
2716 			kmstest_pipe_name(pipe->pipe), plane->index, igt_plane_prop_names[i],
2717 			plane->values[i], plane->values[i]);
2718 
2719 		igt_assert(plane->props[i]);
2720 
2721 		ret = igt_plane_set_property(plane,
2722 					     plane->props[i],
2723 					     plane->values[i]);
2724 
2725 		CHECK_RETURN(ret, fail_on_error);
2726 	}
2727 
2728 	return 0;
2729 }
2730 
2731 /*
2732  * Commit position and fb changes to a cursor via legacy ioctl's.  If commit
2733  * fails, we'll either fail immediately (for tests that expect the commit to
2734  * succeed) or return the failure code (for tests that expect a specific error
2735  * code).
2736  */
igt_cursor_commit_legacy(igt_plane_t * cursor,igt_pipe_t * pipe,bool fail_on_error)2737 static int igt_cursor_commit_legacy(igt_plane_t *cursor,
2738 				    igt_pipe_t *pipe,
2739 				    bool fail_on_error)
2740 {
2741 	igt_display_t *display = pipe->display;
2742 	uint32_t crtc_id = pipe->crtc_id;
2743 	int ret;
2744 
2745 	if (igt_plane_is_prop_changed(cursor, IGT_PLANE_FB_ID) ||
2746 	    igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_W) ||
2747 	    igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_H)) {
2748 		if (cursor->gem_handle)
2749 			LOG(display,
2750 			    "SetCursor pipe %s, fb %u %dx%d\n",
2751 			    kmstest_pipe_name(pipe->pipe),
2752 			    cursor->gem_handle,
2753 			    (unsigned)cursor->values[IGT_PLANE_CRTC_W],
2754 			    (unsigned)cursor->values[IGT_PLANE_CRTC_H]);
2755 		else
2756 			LOG(display,
2757 			    "SetCursor pipe %s, disabling\n",
2758 			    kmstest_pipe_name(pipe->pipe));
2759 
2760 		ret = drmModeSetCursor(display->drm_fd, crtc_id,
2761 				       cursor->gem_handle,
2762 				       cursor->values[IGT_PLANE_CRTC_W],
2763 				       cursor->values[IGT_PLANE_CRTC_H]);
2764 		CHECK_RETURN(ret, fail_on_error);
2765 	}
2766 
2767 	if (igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_X) ||
2768 	    igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_Y)) {
2769 		int x = cursor->values[IGT_PLANE_CRTC_X];
2770 		int y = cursor->values[IGT_PLANE_CRTC_Y];
2771 
2772 		LOG(display,
2773 		    "MoveCursor pipe %s, (%d, %d)\n",
2774 		    kmstest_pipe_name(pipe->pipe),
2775 		    x, y);
2776 
2777 		ret = drmModeMoveCursor(display->drm_fd, crtc_id, x, y);
2778 		CHECK_RETURN(ret, fail_on_error);
2779 	}
2780 
2781 	return 0;
2782 }
2783 
2784 /*
2785  * Commit position and fb changes to a primary plane via the legacy interface
2786  * (setmode).
2787  */
igt_primary_plane_commit_legacy(igt_plane_t * primary,igt_pipe_t * pipe,bool fail_on_error)2788 static int igt_primary_plane_commit_legacy(igt_plane_t *primary,
2789 					   igt_pipe_t *pipe,
2790 					   bool fail_on_error)
2791 {
2792 	struct igt_display *display = primary->pipe->display;
2793 	igt_output_t *output = igt_pipe_get_output(pipe);
2794 	drmModeModeInfo *mode;
2795 	uint32_t fb_id, crtc_id;
2796 	int ret;
2797 
2798 	/* Primary planes can't be windowed when using a legacy commit */
2799 	igt_assert((primary->values[IGT_PLANE_CRTC_X] == 0 && primary->values[IGT_PLANE_CRTC_Y] == 0));
2800 
2801 	/* nor rotated */
2802 	if (!pipe->display->first_commit)
2803 		igt_assert(!igt_plane_is_prop_changed(primary, IGT_PLANE_ROTATION));
2804 
2805 	if (!igt_plane_is_prop_changed(primary, IGT_PLANE_FB_ID) &&
2806 	    !(primary->changed & IGT_PLANE_COORD_CHANGED_MASK) &&
2807 	    !igt_pipe_obj_is_prop_changed(primary->pipe, IGT_CRTC_MODE_ID))
2808 		return 0;
2809 
2810 	crtc_id = pipe->crtc_id;
2811 	fb_id = output ? igt_plane_get_fb_id(primary) : 0;
2812 	if (fb_id)
2813 		mode = igt_output_get_mode(output);
2814 	else
2815 		mode = NULL;
2816 
2817 	if (fb_id) {
2818 		uint32_t src_x = primary->values[IGT_PLANE_SRC_X] >> 16;
2819 		uint32_t src_y = primary->values[IGT_PLANE_SRC_Y] >> 16;
2820 
2821 		LOG(display,
2822 		    "%s: SetCrtc pipe %s, fb %u, src (%d, %d), "
2823 		    "mode %dx%d\n",
2824 		    igt_output_name(output),
2825 		    kmstest_pipe_name(pipe->pipe),
2826 		    fb_id,
2827 		    src_x, src_y,
2828 		    mode->hdisplay, mode->vdisplay);
2829 
2830 		ret = drmModeSetCrtc(display->drm_fd,
2831 				     crtc_id,
2832 				     fb_id,
2833 				     src_x, src_y,
2834 				     &output->id,
2835 				     1,
2836 				     mode);
2837 	} else {
2838 		LOG(display,
2839 		    "SetCrtc pipe %s, disabling\n",
2840 		    kmstest_pipe_name(pipe->pipe));
2841 
2842 		ret = drmModeSetCrtc(display->drm_fd,
2843 				     crtc_id,
2844 				     fb_id,
2845 				     0, 0, /* x, y */
2846 				     NULL, /* connectors */
2847 				     0,    /* n_connectors */
2848 				     NULL  /* mode */);
2849 	}
2850 
2851 	CHECK_RETURN(ret, fail_on_error);
2852 
2853 	return 0;
2854 }
2855 
igt_plane_fixup_rotation(igt_plane_t * plane,igt_pipe_t * pipe)2856 static int igt_plane_fixup_rotation(igt_plane_t *plane,
2857 				    igt_pipe_t *pipe)
2858 {
2859 	int ret;
2860 
2861 	if (!igt_plane_has_prop(plane, IGT_PLANE_ROTATION))
2862 		return 0;
2863 
2864 	LOG(pipe->display, "Fixing up initial rotation pipe %s, plane %d\n",
2865 	    kmstest_pipe_name(pipe->pipe), plane->index);
2866 
2867 	/* First try the easy case, can we change rotation without problems? */
2868 	ret = igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2869 				     plane->values[IGT_PLANE_ROTATION]);
2870 	if (!ret)
2871 		return 0;
2872 
2873 	/* Disable the plane, while we tinker with rotation */
2874 	ret = drmModeSetPlane(pipe->display->drm_fd,
2875 			      plane->drm_plane->plane_id,
2876 			      pipe->crtc_id, 0, /* fb_id */
2877 			      0, /* flags */
2878 			      0, 0, 0, 0, /* crtc_x, crtc_y, crtc_w, crtc_h */
2879 			      IGT_FIXED(0,0), IGT_FIXED(0,0), /* src_x, src_y */
2880 			      IGT_FIXED(0,0), IGT_FIXED(0,0)); /* src_w, src_h */
2881 
2882 	if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY)
2883 		return ret;
2884 
2885 	/* For primary plane, fall back to disabling the crtc. */
2886 	if (ret) {
2887 		ret = drmModeSetCrtc(pipe->display->drm_fd,
2888 				     pipe->crtc_id, 0, 0, 0, NULL, 0, NULL);
2889 
2890 		if (ret)
2891 			return ret;
2892 	}
2893 
2894 	/* and finally, set rotation property. */
2895 	return igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2896 				      plane->values[IGT_PLANE_ROTATION]);
2897 }
2898 
2899 /*
2900  * Commit position and fb changes to a plane.  The value of @s will determine
2901  * which API is used to do the programming.
2902  */
igt_plane_commit(igt_plane_t * plane,igt_pipe_t * pipe,enum igt_commit_style s,bool fail_on_error)2903 static int igt_plane_commit(igt_plane_t *plane,
2904 			    igt_pipe_t *pipe,
2905 			    enum igt_commit_style s,
2906 			    bool fail_on_error)
2907 {
2908 	if (pipe->display->first_commit || (s == COMMIT_UNIVERSAL &&
2909 	     igt_plane_is_prop_changed(plane, IGT_PLANE_ROTATION))) {
2910 		int ret;
2911 
2912 		ret = igt_plane_fixup_rotation(plane, pipe);
2913 		CHECK_RETURN(ret, fail_on_error);
2914 	}
2915 
2916 	if (plane->type == DRM_PLANE_TYPE_CURSOR && s == COMMIT_LEGACY) {
2917 		return igt_cursor_commit_legacy(plane, pipe, fail_on_error);
2918 	} else if (plane->type == DRM_PLANE_TYPE_PRIMARY && s == COMMIT_LEGACY) {
2919 		return igt_primary_plane_commit_legacy(plane, pipe,
2920 						       fail_on_error);
2921 	} else {
2922 		return igt_drm_plane_commit(plane, pipe, fail_on_error);
2923 	}
2924 }
2925 
is_atomic_prop(enum igt_atomic_crtc_properties prop)2926 static bool is_atomic_prop(enum igt_atomic_crtc_properties prop)
2927 {
2928        if (prop == IGT_CRTC_MODE_ID ||
2929 	   prop == IGT_CRTC_ACTIVE ||
2930 	   prop == IGT_CRTC_OUT_FENCE_PTR)
2931 		return true;
2932 
2933 	return false;
2934 }
2935 
2936 /*
2937  * Commit all plane changes to an output.  Note that if @s is COMMIT_LEGACY,
2938  * enabling/disabling the primary plane will also enable/disable the CRTC.
2939  *
2940  * If @fail_on_error is true, any failure to commit plane state will lead
2941  * to subtest failure in the specific function where the failure occurs.
2942  * Otherwise, the first error code encountered will be returned and no
2943  * further programming will take place, which may result in some changes
2944  * taking effect and others not taking effect.
2945  */
igt_pipe_commit(igt_pipe_t * pipe,enum igt_commit_style s,bool fail_on_error)2946 static int igt_pipe_commit(igt_pipe_t *pipe,
2947 			   enum igt_commit_style s,
2948 			   bool fail_on_error)
2949 {
2950 	int i;
2951 	int ret;
2952 
2953 	for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
2954 		if (igt_pipe_obj_is_prop_changed(pipe, i) &&
2955 		    !is_atomic_prop(i)) {
2956 			igt_assert(pipe->props[i]);
2957 
2958 			ret = drmModeObjectSetProperty(pipe->display->drm_fd,
2959 				pipe->crtc_id, DRM_MODE_OBJECT_CRTC,
2960 				pipe->props[i], pipe->values[i]);
2961 
2962 			CHECK_RETURN(ret, fail_on_error);
2963 		}
2964 
2965 	for (i = 0; i < pipe->n_planes; i++) {
2966 		igt_plane_t *plane = &pipe->planes[i];
2967 
2968 		/* skip planes that are handled by another pipe */
2969 		if (plane->ref->pipe != pipe)
2970 			continue;
2971 
2972 		ret = igt_plane_commit(plane, pipe, s, fail_on_error);
2973 		CHECK_RETURN(ret, fail_on_error);
2974 	}
2975 
2976 	return 0;
2977 }
2978 
igt_output_commit(igt_output_t * output,enum igt_commit_style s,bool fail_on_error)2979 static int igt_output_commit(igt_output_t *output,
2980 			     enum igt_commit_style s,
2981 			     bool fail_on_error)
2982 {
2983 	int i, ret;
2984 
2985 	for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
2986 		if (!igt_output_is_prop_changed(output, i))
2987 			continue;
2988 
2989 		/* CRTC_ID is set by calling drmModeSetCrtc in the legacy path. */
2990 		if (i == IGT_CONNECTOR_CRTC_ID)
2991 			continue;
2992 
2993 		igt_assert(output->props[i]);
2994 
2995 		if (s == COMMIT_LEGACY)
2996 			ret = drmModeConnectorSetProperty(output->display->drm_fd, output->id,
2997 							  output->props[i], output->values[i]);
2998 		else
2999 			ret = drmModeObjectSetProperty(output->display->drm_fd, output->id,
3000 						       DRM_MODE_OBJECT_CONNECTOR,
3001 						       output->props[i], output->values[i]);
3002 
3003 		CHECK_RETURN(ret, fail_on_error);
3004 	}
3005 
3006 	return 0;
3007 }
3008 
igt_mode_object_get_prop(igt_display_t * display,uint32_t object_type,uint32_t object_id,uint32_t prop)3009 static uint64_t igt_mode_object_get_prop(igt_display_t *display,
3010 					 uint32_t object_type,
3011 					 uint32_t object_id,
3012 					 uint32_t prop)
3013 {
3014 	drmModeObjectPropertiesPtr proplist;
3015 	bool found = false;
3016 	int i;
3017 	uint64_t ret;
3018 
3019 	proplist = drmModeObjectGetProperties(display->drm_fd, object_id, object_type);
3020 	for (i = 0; i < proplist->count_props; i++) {
3021 		if (proplist->props[i] != prop)
3022 			continue;
3023 
3024 		found = true;
3025 		break;
3026 	}
3027 
3028 	igt_assert(found);
3029 
3030 	ret = proplist->prop_values[i];
3031 
3032 	drmModeFreeObjectProperties(proplist);
3033 	return ret;
3034 }
3035 
3036 /**
3037  * igt_plane_get_prop:
3038  * @plane: Target plane.
3039  * @prop: Property to check.
3040  *
3041  * Return current value on a plane for a given property.
3042  *
3043  * Returns: The value the property is set to, if this
3044  * is a blob, the blob id is returned. This can be passed
3045  * to drmModeGetPropertyBlob() to get the contents of the blob.
3046  */
igt_plane_get_prop(igt_plane_t * plane,enum igt_atomic_plane_properties prop)3047 uint64_t igt_plane_get_prop(igt_plane_t *plane, enum igt_atomic_plane_properties prop)
3048 {
3049 	igt_assert(igt_plane_has_prop(plane, prop));
3050 
3051 	return igt_mode_object_get_prop(plane->pipe->display, DRM_MODE_OBJECT_PLANE,
3052 					plane->drm_plane->plane_id, plane->props[prop]);
3053 }
3054 
igt_mode_object_get_prop_enum_value(int drm_fd,uint32_t id,const char * str,uint64_t * val)3055 static bool igt_mode_object_get_prop_enum_value(int drm_fd, uint32_t id, const char *str, uint64_t *val)
3056 {
3057 	drmModePropertyPtr prop = drmModeGetProperty(drm_fd, id);
3058 	int i;
3059 
3060 	igt_assert(id);
3061 	igt_assert(prop);
3062 
3063 	for (i = 0; i < prop->count_enums; i++)
3064 		if (!strcmp(str, prop->enums[i].name)) {
3065 			*val = prop->enums[i].value;
3066 			drmModeFreeProperty(prop);
3067 			return true;
3068 		}
3069 
3070 	return false;
3071 }
3072 
igt_plane_try_prop_enum(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const char * val)3073 bool igt_plane_try_prop_enum(igt_plane_t *plane,
3074 			     enum igt_atomic_plane_properties prop,
3075 			     const char *val)
3076 {
3077 	igt_display_t *display = plane->pipe->display;
3078 	uint64_t uval;
3079 
3080 	igt_assert(plane->props[prop]);
3081 
3082 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3083 						 plane->props[prop], val, &uval))
3084 		return false;
3085 
3086 	igt_plane_set_prop_value(plane, prop, uval);
3087 	return true;
3088 }
3089 
igt_plane_set_prop_enum(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const char * val)3090 void igt_plane_set_prop_enum(igt_plane_t *plane,
3091 			     enum igt_atomic_plane_properties prop,
3092 			     const char *val)
3093 {
3094 	igt_assert(igt_plane_try_prop_enum(plane, prop, val));
3095 }
3096 
3097 /**
3098  * igt_plane_replace_prop_blob:
3099  * @plane: plane to set property on.
3100  * @prop: property for which the blob will be replaced.
3101  * @ptr: Pointer to contents for the property.
3102  * @length: Length of contents.
3103  *
3104  * This function will destroy the old property blob for the given property,
3105  * and will create a new property blob with the values passed to this function.
3106  *
3107  * The new property blob will be committed when you call igt_display_commit(),
3108  * igt_display_commit2() or igt_display_commit_atomic().
3109  */
3110 void
igt_plane_replace_prop_blob(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const void * ptr,size_t length)3111 igt_plane_replace_prop_blob(igt_plane_t *plane, enum igt_atomic_plane_properties prop, const void *ptr, size_t length)
3112 {
3113 	igt_display_t *display = plane->pipe->display;
3114 	uint64_t *blob = &plane->values[prop];
3115 	uint32_t blob_id = 0;
3116 
3117 	if (*blob != 0)
3118 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3119 						      *blob) == 0);
3120 
3121 	if (length > 0)
3122 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3123 						     ptr, length, &blob_id) == 0);
3124 
3125 	*blob = blob_id;
3126 	igt_plane_set_prop_changed(plane, prop);
3127 }
3128 
3129 /**
3130  * igt_output_get_prop:
3131  * @output: Target output.
3132  * @prop: Property to return.
3133  *
3134  * Return current value on an output for a given property.
3135  *
3136  * Returns: The value the property is set to, if this
3137  * is a blob, the blob id is returned. This can be passed
3138  * to drmModeGetPropertyBlob() to get the contents of the blob.
3139  */
igt_output_get_prop(igt_output_t * output,enum igt_atomic_connector_properties prop)3140 uint64_t igt_output_get_prop(igt_output_t *output, enum igt_atomic_connector_properties prop)
3141 {
3142 	igt_assert(igt_output_has_prop(output, prop));
3143 
3144 	return igt_mode_object_get_prop(output->display, DRM_MODE_OBJECT_CONNECTOR,
3145 					output->id, output->props[prop]);
3146 }
3147 
igt_output_try_prop_enum(igt_output_t * output,enum igt_atomic_connector_properties prop,const char * val)3148 bool igt_output_try_prop_enum(igt_output_t *output,
3149 			      enum igt_atomic_connector_properties prop,
3150 			      const char *val)
3151 {
3152 	igt_display_t *display = output->display;
3153 	uint64_t uval;
3154 
3155 	igt_assert(output->props[prop]);
3156 
3157 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3158 						 output->props[prop], val, &uval))
3159 		return false;
3160 
3161 	igt_output_set_prop_value(output, prop, uval);
3162 	return true;
3163 }
3164 
igt_output_set_prop_enum(igt_output_t * output,enum igt_atomic_connector_properties prop,const char * val)3165 void igt_output_set_prop_enum(igt_output_t *output,
3166 			      enum igt_atomic_connector_properties prop,
3167 			      const char *val)
3168 {
3169 	igt_assert(igt_output_try_prop_enum(output, prop, val));
3170 }
3171 
3172 /**
3173  * igt_output_replace_prop_blob:
3174  * @output: output to set property on.
3175  * @prop: property for which the blob will be replaced.
3176  * @ptr: Pointer to contents for the property.
3177  * @length: Length of contents.
3178  *
3179  * This function will destroy the old property blob for the given property,
3180  * and will create a new property blob with the values passed to this function.
3181  *
3182  * The new property blob will be committed when you call igt_display_commit(),
3183  * igt_display_commit2() or igt_display_commit_atomic().
3184  */
3185 void
igt_output_replace_prop_blob(igt_output_t * output,enum igt_atomic_connector_properties prop,const void * ptr,size_t length)3186 igt_output_replace_prop_blob(igt_output_t *output, enum igt_atomic_connector_properties prop, const void *ptr, size_t length)
3187 {
3188 	igt_display_t *display = output->display;
3189 	uint64_t *blob = &output->values[prop];
3190 	uint32_t blob_id = 0;
3191 
3192 	if (*blob != 0)
3193 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3194 						      *blob) == 0);
3195 
3196 	if (length > 0)
3197 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3198 						     ptr, length, &blob_id) == 0);
3199 
3200 	*blob = blob_id;
3201 	igt_output_set_prop_changed(output, prop);
3202 }
3203 
3204 /**
3205  * igt_pipe_obj_get_prop:
3206  * @pipe: Target pipe.
3207  * @prop: Property to return.
3208  *
3209  * Return current value on a pipe for a given property.
3210  *
3211  * Returns: The value the property is set to, if this
3212  * is a blob, the blob id is returned. This can be passed
3213  * to drmModeGetPropertyBlob() to get the contents of the blob.
3214  */
igt_pipe_obj_get_prop(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop)3215 uint64_t igt_pipe_obj_get_prop(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
3216 {
3217 	igt_assert(igt_pipe_obj_has_prop(pipe, prop));
3218 
3219 	return igt_mode_object_get_prop(pipe->display, DRM_MODE_OBJECT_CRTC,
3220 					pipe->crtc_id, pipe->props[prop]);
3221 }
3222 
igt_pipe_obj_try_prop_enum(igt_pipe_t * pipe_obj,enum igt_atomic_crtc_properties prop,const char * val)3223 bool igt_pipe_obj_try_prop_enum(igt_pipe_t *pipe_obj,
3224 				enum igt_atomic_crtc_properties prop,
3225 				const char *val)
3226 {
3227 	igt_display_t *display = pipe_obj->display;
3228 	uint64_t uval;
3229 
3230 	igt_assert(pipe_obj->props[prop]);
3231 
3232 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3233 						 pipe_obj->props[prop], val, &uval))
3234 		return false;
3235 
3236 	igt_pipe_obj_set_prop_value(pipe_obj, prop, uval);
3237 	return true;
3238 }
3239 
igt_pipe_obj_set_prop_enum(igt_pipe_t * pipe_obj,enum igt_atomic_crtc_properties prop,const char * val)3240 void igt_pipe_obj_set_prop_enum(igt_pipe_t *pipe_obj,
3241 				enum igt_atomic_crtc_properties prop,
3242 				const char *val)
3243 {
3244 	igt_assert(igt_pipe_obj_try_prop_enum(pipe_obj, prop, val));
3245 }
3246 
3247 /**
3248  * igt_pipe_obj_replace_prop_blob:
3249  * @pipe: pipe to set property on.
3250  * @prop: property for which the blob will be replaced.
3251  * @ptr: Pointer to contents for the property.
3252  * @length: Length of contents.
3253  *
3254  * This function will destroy the old property blob for the given property,
3255  * and will create a new property blob with the values passed to this function.
3256  *
3257  * The new property blob will be committed when you call igt_display_commit(),
3258  * igt_display_commit2() or igt_display_commit_atomic().
3259  *
3260  * Please use igt_output_override_mode() if you want to set #IGT_CRTC_MODE_ID,
3261  * it works better with legacy commit.
3262  */
3263 void
igt_pipe_obj_replace_prop_blob(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop,const void * ptr,size_t length)3264 igt_pipe_obj_replace_prop_blob(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop, const void *ptr, size_t length)
3265 {
3266 	igt_display_t *display = pipe->display;
3267 	uint64_t *blob = &pipe->values[prop];
3268 	uint32_t blob_id = 0;
3269 
3270 	if (*blob != 0)
3271 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3272 						      *blob) == 0);
3273 
3274 	if (length > 0)
3275 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3276 						     ptr, length, &blob_id) == 0);
3277 
3278 	*blob = blob_id;
3279 	igt_pipe_obj_set_prop_changed(pipe, prop);
3280 }
3281 
3282 /*
3283  * Add crtc property changes to the atomic property set
3284  */
igt_atomic_prepare_crtc_commit(igt_pipe_t * pipe_obj,drmModeAtomicReq * req)3285 static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
3286 {
3287 	int i;
3288 
3289 	for (i = 0; i < IGT_NUM_CRTC_PROPS; i++) {
3290 		if (!igt_pipe_obj_is_prop_changed(pipe_obj, i))
3291 			continue;
3292 
3293 		igt_debug("Pipe %s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3294 			kmstest_pipe_name(pipe_obj->pipe), igt_crtc_prop_names[i],
3295 			pipe_obj->values[i], pipe_obj->values[i]);
3296 
3297 		igt_assert_lt(0, drmModeAtomicAddProperty(req, pipe_obj->crtc_id, pipe_obj->props[i], pipe_obj->values[i]));
3298 	}
3299 
3300 	if (pipe_obj->out_fence_fd != -1) {
3301 		close(pipe_obj->out_fence_fd);
3302 		pipe_obj->out_fence_fd = -1;
3303 	}
3304 }
3305 
3306 /*
3307  * Add connector property changes to the atomic property set
3308  */
igt_atomic_prepare_connector_commit(igt_output_t * output,drmModeAtomicReq * req)3309 static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
3310 {
3311 
3312 	int i;
3313 
3314 	for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
3315 		if (!igt_output_is_prop_changed(output, i))
3316 			continue;
3317 
3318 		/* it's an error to try an unsupported feature */
3319 		igt_assert(output->props[i]);
3320 
3321 		igt_debug("%s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3322 			  igt_output_name(output), igt_connector_prop_names[i],
3323 			  output->values[i], output->values[i]);
3324 
3325 		igt_assert_lt(0, drmModeAtomicAddProperty(req,
3326 					  output->config.connector->connector_id,
3327 					  output->props[i],
3328 					  output->values[i]));
3329 	}
3330 }
3331 
3332 /*
3333  * Commit all the changes of all the planes,crtcs, connectors
3334  * atomically using drmModeAtomicCommit()
3335  */
igt_atomic_commit(igt_display_t * display,uint32_t flags,void * user_data)3336 static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_data)
3337 {
3338 
3339 	int ret = 0, i;
3340 	enum pipe pipe;
3341 	drmModeAtomicReq *req;
3342 	igt_output_t *output;
3343 
3344 	if (display->is_atomic != 1)
3345 		return -1;
3346 	req = drmModeAtomicAlloc();
3347 
3348 	for_each_pipe(display, pipe) {
3349 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
3350 		igt_plane_t *plane;
3351 
3352 		/*
3353 		 * Add CRTC Properties to the property set
3354 		 */
3355 		if (pipe_obj->changed)
3356 			igt_atomic_prepare_crtc_commit(pipe_obj, req);
3357 
3358 		for_each_plane_on_pipe(display, pipe, plane) {
3359 			/* skip planes that are handled by another pipe */
3360 			if (plane->ref->pipe != pipe_obj)
3361 				continue;
3362 
3363 			if (plane->changed)
3364 				igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
3365 		}
3366 
3367 	}
3368 
3369 	for (i = 0; i < display->n_outputs; i++) {
3370 		output = &display->outputs[i];
3371 
3372 		if (!output->config.connector || !output->changed)
3373 			continue;
3374 
3375 		LOG(display, "%s: preparing atomic, pipe: %s\n",
3376 		    igt_output_name(output),
3377 		    kmstest_pipe_name(output->config.pipe));
3378 
3379 		igt_atomic_prepare_connector_commit(output, req);
3380 	}
3381 
3382 	ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data);
3383 
3384 	drmModeAtomicFree(req);
3385 	return ret;
3386 
3387 }
3388 
3389 static void
display_commit_changed(igt_display_t * display,enum igt_commit_style s)3390 display_commit_changed(igt_display_t *display, enum igt_commit_style s)
3391 {
3392 	int i;
3393 	enum pipe pipe;
3394 
3395 	for_each_pipe(display, pipe) {
3396 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
3397 		igt_plane_t *plane;
3398 
3399 		if (s == COMMIT_ATOMIC) {
3400 			if (igt_pipe_obj_is_prop_changed(pipe_obj, IGT_CRTC_OUT_FENCE_PTR))
3401 				igt_assert(pipe_obj->out_fence_fd >= 0);
3402 
3403 			pipe_obj->values[IGT_CRTC_OUT_FENCE_PTR] = 0;
3404 			pipe_obj->changed = 0;
3405 		} else {
3406 			for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
3407 				if (!is_atomic_prop(i))
3408 					igt_pipe_obj_clear_prop_changed(pipe_obj, i);
3409 
3410 			if (s != COMMIT_UNIVERSAL) {
3411 				igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3412 				igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_ACTIVE);
3413 			}
3414 		}
3415 
3416 		for_each_plane_on_pipe(display, pipe, plane) {
3417 			if (s == COMMIT_ATOMIC) {
3418 				int fd;
3419 				plane->changed = 0;
3420 
3421 				fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3422 				if (fd != -1)
3423 					close(fd);
3424 
3425 				/* reset fence_fd to prevent it from being set for the next commit */
3426 				plane->values[IGT_PLANE_IN_FENCE_FD] = -1;
3427 			} else {
3428 				plane->changed &= ~IGT_PLANE_COORD_CHANGED_MASK;
3429 
3430 				igt_plane_clear_prop_changed(plane, IGT_PLANE_CRTC_ID);
3431 				igt_plane_clear_prop_changed(plane, IGT_PLANE_FB_ID);
3432 
3433 				if (s != COMMIT_LEGACY ||
3434 				    !(plane->type == DRM_PLANE_TYPE_PRIMARY ||
3435 				      plane->type == DRM_PLANE_TYPE_CURSOR))
3436 					plane->changed &= ~LEGACY_PLANE_COMMIT_MASK;
3437 
3438 				if (display->first_commit)
3439 					igt_plane_clear_prop_changed(plane, IGT_PLANE_ROTATION);
3440 			}
3441 		}
3442 	}
3443 
3444 	for (i = 0; i < display->n_outputs; i++) {
3445 		igt_output_t *output = &display->outputs[i];
3446 
3447 		if (s != COMMIT_UNIVERSAL)
3448 			output->changed = 0;
3449 		else
3450 			/* no modeset in universal commit, no change to crtc. */
3451 			output->changed &= 1 << IGT_CONNECTOR_CRTC_ID;
3452 	}
3453 
3454 	if (display->first_commit) {
3455 		igt_reset_fifo_underrun_reporting(display->drm_fd);
3456 
3457 		igt_display_drop_events(display);
3458 
3459 		display->first_commit = false;
3460 	}
3461 }
3462 
3463 /*
3464  * Commit all plane changes across all outputs of the display.
3465  *
3466  * If @fail_on_error is true, any failure to commit plane state will lead
3467  * to subtest failure in the specific function where the failure occurs.
3468  * Otherwise, the first error code encountered will be returned and no
3469  * further programming will take place, which may result in some changes
3470  * taking effect and others not taking effect.
3471  */
do_display_commit(igt_display_t * display,enum igt_commit_style s,bool fail_on_error)3472 static int do_display_commit(igt_display_t *display,
3473 			     enum igt_commit_style s,
3474 			     bool fail_on_error)
3475 {
3476 	int i, ret = 0;
3477 	enum pipe pipe;
3478 	LOG_INDENT(display, "commit");
3479 
3480 	/* someone managed to bypass igt_display_require, catch them */
3481 	assert(display->n_pipes && display->n_outputs);
3482 
3483 	igt_display_refresh(display);
3484 
3485 	if (s == COMMIT_ATOMIC) {
3486 		ret = igt_atomic_commit(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
3487 	} else {
3488 		for_each_pipe(display, pipe) {
3489 			igt_pipe_t *pipe_obj = &display->pipes[pipe];
3490 
3491 			ret = igt_pipe_commit(pipe_obj, s, fail_on_error);
3492 			if (ret)
3493 				break;
3494 		}
3495 
3496 		for (i = 0; !ret && i < display->n_outputs; i++)
3497 			ret = igt_output_commit(&display->outputs[i], s, fail_on_error);
3498 	}
3499 
3500 	LOG_UNINDENT(display);
3501 	CHECK_RETURN(ret, fail_on_error);
3502 
3503 	display_commit_changed(display, s);
3504 
3505 	igt_debug_wait_for_keypress("modeset");
3506 
3507 	return 0;
3508 }
3509 
3510 /**
3511  * igt_display_try_commit_atomic:
3512  * @display: #igt_display_t to commit.
3513  * @flags: Flags passed to drmModeAtomicCommit.
3514  * @user_data: User defined pointer passed to drmModeAtomicCommit.
3515  *
3516  * This function is similar to #igt_display_try_commit2, but is
3517  * used when you want to pass different flags to the actual commit.
3518  *
3519  * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3520  * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3521  * or DRM_MODE_ATOMIC_TEST_ONLY.
3522  *
3523  * @user_data is returned in the event if you pass
3524  * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3525  *
3526  * This function will return an error if commit fails, instead of
3527  * aborting the test.
3528  */
igt_display_try_commit_atomic(igt_display_t * display,uint32_t flags,void * user_data)3529 int igt_display_try_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3530 {
3531 	int ret;
3532 
3533 	/* someone managed to bypass igt_display_require, catch them */
3534 	assert(display->n_pipes && display->n_outputs);
3535 
3536 	LOG_INDENT(display, "commit");
3537 
3538 	igt_display_refresh(display);
3539 
3540 	ret = igt_atomic_commit(display, flags, user_data);
3541 
3542 	LOG_UNINDENT(display);
3543 
3544 	if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))
3545 		return ret;
3546 
3547 	if (display->first_commit)
3548 		igt_fail_on_f(flags & (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK),
3549 			      "First commit has to drop all stale events\n");
3550 
3551 	display_commit_changed(display, COMMIT_ATOMIC);
3552 
3553 	igt_debug_wait_for_keypress("modeset");
3554 
3555 	return 0;
3556 }
3557 
3558 /**
3559  * igt_display_commit_atomic:
3560  * @display: #igt_display_t to commit.
3561  * @flags: Flags passed to drmModeAtomicCommit.
3562  * @user_data: User defined pointer passed to drmModeAtomicCommit.
3563  *
3564  * This function is similar to #igt_display_commit2, but is
3565  * used when you want to pass different flags to the actual commit.
3566  *
3567  * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3568  * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3569  * or DRM_MODE_ATOMIC_TEST_ONLY.
3570  *
3571  * @user_data is returned in the event if you pass
3572  * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3573  *
3574  * This function will abort the test if commit fails.
3575  */
igt_display_commit_atomic(igt_display_t * display,uint32_t flags,void * user_data)3576 void igt_display_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3577 {
3578 	int ret = igt_display_try_commit_atomic(display, flags, user_data);
3579 
3580 	igt_assert_eq(ret, 0);
3581 }
3582 
3583 /**
3584  * igt_display_commit2:
3585  * @display: DRM device handle
3586  * @s: Commit style
3587  *
3588  * Commits framebuffer and positioning changes to all planes of each display
3589  * pipe, using a specific API to perform the programming.  This function should
3590  * be used to exercise a specific driver programming API; igt_display_commit
3591  * should be used instead if the API used is unimportant to the test being run.
3592  *
3593  * This function should only be used to commit changes that are expected to
3594  * succeed, since any failure during the commit process will cause the IGT
3595  * subtest to fail.  To commit changes that are expected to fail, use
3596  * @igt_try_display_commit2 instead.
3597  *
3598  * Returns: 0 upon success.  This function will never return upon failure
3599  * since igt_fail() at lower levels will longjmp out of it.
3600  */
igt_display_commit2(igt_display_t * display,enum igt_commit_style s)3601 int igt_display_commit2(igt_display_t *display,
3602 		       enum igt_commit_style s)
3603 {
3604 	do_display_commit(display, s, true);
3605 
3606 	return 0;
3607 }
3608 
3609 /**
3610  * igt_display_try_commit2:
3611  * @display: DRM device handle
3612  * @s: Commit style
3613  *
3614  * Attempts to commit framebuffer and positioning changes to all planes of each
3615  * display pipe.  This function should be used to commit changes that are
3616  * expected to fail, so that the error code can be checked for correctness.
3617  * For changes that are expected to succeed, use @igt_display_commit instead.
3618  *
3619  * Note that in non-atomic commit styles, no display programming will be
3620  * performed after the first failure is encountered, so only some of the
3621  * operations requested by a test may have been completed.  Tests that catch
3622  * errors returned by this function should take care to restore the display to
3623  * a sane state after a failure is detected.
3624  *
3625  * Returns: 0 upon success, otherwise the error code of the first error
3626  * encountered.
3627  */
igt_display_try_commit2(igt_display_t * display,enum igt_commit_style s)3628 int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s)
3629 {
3630 	return do_display_commit(display, s, false);
3631 }
3632 
3633 /**
3634  * igt_display_commit:
3635  * @display: DRM device handle
3636  *
3637  * Commits framebuffer and positioning changes to all planes of each display
3638  * pipe.
3639  *
3640  * Returns: 0 upon success.  This function will never return upon failure
3641  * since igt_fail() at lower levels will longjmp out of it.
3642  */
igt_display_commit(igt_display_t * display)3643 int igt_display_commit(igt_display_t *display)
3644 {
3645 	return igt_display_commit2(display, COMMIT_LEGACY);
3646 }
3647 
3648 /**
3649  * igt_display_drop_events:
3650  * @display: DRM device handle
3651  *
3652  * Nonblockingly reads all current events and drops them, for highest
3653  * reliablility, call igt_display_commit2() first to flush all outstanding
3654  * events.
3655  *
3656  * This will be called on the first commit after igt_display_reset() too,
3657  * to make sure any stale events are flushed.
3658  *
3659  * Returns: Number of dropped events.
3660  */
igt_display_drop_events(igt_display_t * display)3661 int igt_display_drop_events(igt_display_t *display)
3662 {
3663 	int ret = 0;
3664 
3665 	/* Clear all events from drm fd. */
3666 	struct pollfd pfd = {
3667 		.fd = display->drm_fd,
3668 		.events = POLLIN
3669 	};
3670 
3671 	while (poll(&pfd, 1, 0) > 0) {
3672 		struct drm_event *ev;
3673 		char buf[4096];
3674 		ssize_t retval;
3675 
3676 		retval = read(display->drm_fd, &buf, sizeof(buf));
3677 		igt_assert_lt(0, retval);
3678 
3679 		for (int i = 0; i < retval; i += ev->length) {
3680 			ev = (struct drm_event *)&buf[i];
3681 
3682 			igt_info("Dropping event type %u length %u\n", ev->type, ev->length);
3683 			igt_assert(ev->length + i <= sizeof(buf));
3684 			ret++;
3685 		}
3686 	}
3687 
3688 	return ret;
3689 }
3690 
3691 /**
3692  * igt_output_name:
3693  * @output: Target output
3694  *
3695  * Returns: String representing a connector's name, e.g. "DP-1".
3696  */
igt_output_name(igt_output_t * output)3697 const char *igt_output_name(igt_output_t *output)
3698 {
3699 	return output->name;
3700 }
3701 
3702 /**
3703  * igt_output_get_mode:
3704  * @output: Target output
3705  *
3706  * Get the current mode of the given connector
3707  *
3708  * Returns: A #drmModeModeInfo struct representing the current mode
3709  */
igt_output_get_mode(igt_output_t * output)3710 drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
3711 {
3712 	if (output->use_override_mode)
3713 		return &output->override_mode;
3714 	else
3715 		return &output->config.default_mode;
3716 }
3717 
3718 /**
3719  * igt_output_override_mode:
3720  * @output: Output of which the mode will be overridden
3721  * @mode: New mode, or NULL to disable override.
3722  *
3723  * Overrides the output's mode with @mode, so that it is used instead of the
3724  * mode obtained with get connectors. Note that the mode is used without
3725  * checking if the output supports it, so this might lead to unexpected results.
3726  */
igt_output_override_mode(igt_output_t * output,const drmModeModeInfo * mode)3727 void igt_output_override_mode(igt_output_t *output, const drmModeModeInfo *mode)
3728 {
3729 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3730 
3731 	if (mode)
3732 		output->override_mode = *mode;
3733 
3734 	output->use_override_mode = !!mode;
3735 
3736 	if (pipe) {
3737 		if (output->display->is_atomic)
3738 			igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(*mode));
3739 		else
3740 			igt_pipe_obj_set_prop_changed(pipe, IGT_CRTC_MODE_ID);
3741 	}
3742 }
3743 
3744 /*
3745  * igt_output_set_pipe:
3746  * @output: Target output for which the pipe is being set to
3747  * @pipe: Display pipe to set to
3748  *
3749  * This function sets a @pipe to a specific @output connector by
3750  * setting the CRTC_ID property of the @pipe. The pipe
3751  * is only activated for all pipes except PIPE_NONE.
3752  */
igt_output_set_pipe(igt_output_t * output,enum pipe pipe)3753 void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
3754 {
3755 	igt_display_t *display = output->display;
3756 	igt_pipe_t *old_pipe = NULL, *pipe_obj = NULL;;
3757 
3758 	igt_assert(output->name);
3759 
3760 	if (output->pending_pipe != PIPE_NONE)
3761 		old_pipe = igt_output_get_driving_pipe(output);
3762 
3763 	if (pipe != PIPE_NONE)
3764 		pipe_obj = &display->pipes[pipe];
3765 
3766 	LOG(display, "%s: set_pipe(%s)\n", igt_output_name(output),
3767 	    kmstest_pipe_name(pipe));
3768 	output->pending_pipe = pipe;
3769 
3770 	if (old_pipe) {
3771 		igt_output_t *old_output;
3772 
3773 		old_output = igt_pipe_get_output(old_pipe);
3774 		if (!old_output) {
3775 			if (display->is_atomic)
3776 				igt_pipe_obj_replace_prop_blob(old_pipe, IGT_CRTC_MODE_ID, NULL, 0);
3777 			else
3778 				igt_pipe_obj_set_prop_changed(old_pipe, IGT_CRTC_MODE_ID);
3779 
3780 			igt_pipe_obj_set_prop_value(old_pipe, IGT_CRTC_ACTIVE, 0);
3781 		}
3782 	}
3783 
3784 	igt_output_set_prop_value(output, IGT_CONNECTOR_CRTC_ID, pipe == PIPE_NONE ? 0 : display->pipes[pipe].crtc_id);
3785 
3786 	igt_output_refresh(output);
3787 
3788 	if (pipe_obj) {
3789 		if (display->is_atomic)
3790 			igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
3791 		else
3792 			igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3793 
3794 		igt_pipe_obj_set_prop_value(pipe_obj, IGT_CRTC_ACTIVE, 1);
3795 	}
3796 }
3797 
3798 /*
3799  * igt_pipe_refresh:
3800  * @display: a pointer to an #igt_display_t structure
3801  * @pipe: Pipe to refresh
3802  * @force: Should be set to true if mode_blob is no longer considered
3803  * to be valid, for example after doing an atomic commit during fork or closing display fd.
3804  *
3805  * Requests the pipe to be part of the state on next update.
3806  * This is useful when state may have been out of sync after
3807  * a fork, or we just want to be sure the pipe is included
3808  * in the next commit.
3809  */
igt_pipe_refresh(igt_display_t * display,enum pipe pipe,bool force)3810 void igt_pipe_refresh(igt_display_t *display, enum pipe pipe, bool force)
3811 {
3812 	igt_pipe_t *pipe_obj = &display->pipes[pipe];
3813 
3814 	if (force && display->is_atomic) {
3815 		igt_output_t *output = igt_pipe_get_output(pipe_obj);
3816 
3817 		pipe_obj->values[IGT_CRTC_MODE_ID] = 0;
3818 		if (output)
3819 			igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
3820 	} else
3821 		igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3822 }
3823 
igt_output_get_plane(igt_output_t * output,int plane_idx)3824 igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx)
3825 {
3826 	igt_pipe_t *pipe;
3827 
3828 	pipe = igt_output_get_driving_pipe(output);
3829 	igt_assert(pipe);
3830 
3831 	return igt_pipe_get_plane(pipe, plane_idx);
3832 }
3833 
3834 /**
3835  * igt_output_get_plane_type:
3836  * @output: Target output
3837  * @plane_type: Cursor, primary or an overlay plane
3838  *
3839  * Finds a valid plane type for the given @output otherwise
3840  * the test is skipped if the right combination of @output/@plane_type is not found
3841  *
3842  * Returns: A #igt_plane_t structure that matches the requested plane type
3843  */
igt_output_get_plane_type(igt_output_t * output,int plane_type)3844 igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type)
3845 {
3846 	igt_pipe_t *pipe;
3847 
3848 	pipe = igt_output_get_driving_pipe(output);
3849 	igt_assert(pipe);
3850 
3851 	return igt_pipe_get_plane_type(pipe, plane_type);
3852 }
3853 
3854 /**
3855  * igt_output_count_plane_type:
3856  * @output: Target output
3857  * @plane_type: Cursor, primary or an overlay plane
3858  *
3859  * Counts the number of planes of type @plane_type for the provided @output.
3860  *
3861  * Returns: The number of planes that match the requested plane type
3862  */
igt_output_count_plane_type(igt_output_t * output,int plane_type)3863 int igt_output_count_plane_type(igt_output_t *output, int plane_type)
3864 {
3865 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3866 	igt_assert(pipe);
3867 
3868 	return igt_pipe_count_plane_type(pipe, plane_type);
3869 }
3870 
3871 /**
3872  * igt_output_get_plane_type_index:
3873  * @output: Target output
3874  * @plane_type: Cursor, primary or an overlay plane
3875  * @index: the index of the plane among planes of the same type
3876  *
3877  * Get the @index th plane of type @plane_type for the provided @output.
3878  *
3879  * Returns: The @index th plane that matches the requested plane type
3880  */
igt_output_get_plane_type_index(igt_output_t * output,int plane_type,int index)3881 igt_plane_t *igt_output_get_plane_type_index(igt_output_t *output,
3882 					     int plane_type, int index)
3883 {
3884 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3885 	igt_assert(pipe);
3886 
3887 	return igt_pipe_get_plane_type_index(pipe, plane_type, index);
3888 }
3889 
3890 /**
3891  * igt_plane_set_fb:
3892  * @plane: Plane
3893  * @fb: Framebuffer pointer
3894  *
3895  * Pairs a given @framebuffer to a @plane
3896  *
3897  * This function also sets a default size and position for the framebuffer
3898  * to avoid crashes on applications that ignore to set these.
3899  */
igt_plane_set_fb(igt_plane_t * plane,struct igt_fb * fb)3900 void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb)
3901 {
3902 	igt_pipe_t *pipe = plane->pipe;
3903 	igt_display_t *display = pipe->display;
3904 
3905 	LOG(display, "%s.%d: plane_set_fb(%d)\n", kmstest_pipe_name(pipe->pipe),
3906 	    plane->index, fb ? fb->fb_id : 0);
3907 
3908 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, fb ? pipe->crtc_id : 0);
3909 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, fb ? fb->fb_id : 0);
3910 
3911 	if (plane->type == DRM_PLANE_TYPE_CURSOR && fb)
3912 		plane->gem_handle = fb->gem_handle;
3913 	else
3914 		plane->gem_handle = 0;
3915 
3916 	/* hack to keep tests working that don't call igt_plane_set_size() */
3917 	if (fb) {
3918 		/* set default plane size as fb size */
3919 		igt_plane_set_size(plane, fb->width, fb->height);
3920 
3921 		/* set default src pos/size as fb size */
3922 		igt_fb_set_position(fb, plane, 0, 0);
3923 		igt_fb_set_size(fb, plane, fb->width, fb->height);
3924 
3925 		if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
3926 			igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
3927 				igt_color_encoding_to_str(fb->color_encoding));
3928 		if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
3929 			igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
3930 				igt_color_range_to_str(fb->color_range));
3931 
3932 		/* Hack to prioritize the plane on the pipe that last set fb */
3933 		igt_plane_set_pipe(plane, pipe);
3934 	} else {
3935 		igt_plane_set_size(plane, 0, 0);
3936 
3937 		/* set default src pos/size as fb size */
3938 		igt_fb_set_position(fb, plane, 0, 0);
3939 		igt_fb_set_size(fb, plane, 0, 0);
3940 	}
3941 }
3942 
3943 /**
3944  * igt_plane_set_fence_fd:
3945  * @plane: plane
3946  * @fence_fd: fence fd, disable fence_fd by setting it to -1
3947  *
3948  * This function sets a fence fd to enable a commit to wait for some event to
3949  * occur before completing.
3950  */
igt_plane_set_fence_fd(igt_plane_t * plane,int fence_fd)3951 void igt_plane_set_fence_fd(igt_plane_t *plane, int fence_fd)
3952 {
3953 	int64_t fd;
3954 
3955 	fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3956 	if (fd != -1)
3957 		close(fd);
3958 
3959 	if (fence_fd != -1) {
3960 		fd = dup(fence_fd);
3961 		igt_fail_on(fd == -1);
3962 	} else
3963 		fd = -1;
3964 
3965 	igt_plane_set_prop_value(plane, IGT_PLANE_IN_FENCE_FD, fd);
3966 }
3967 
3968 /**
3969  * igt_plane_set_pipe:
3970  * @plane: Target plane pointer
3971  * @pipe: The pipe to assign the plane to
3972  *
3973  */
igt_plane_set_pipe(igt_plane_t * plane,igt_pipe_t * pipe)3974 void igt_plane_set_pipe(igt_plane_t *plane, igt_pipe_t *pipe)
3975 {
3976 	/*
3977 	 * HACK: Point the global plane back to the local plane.
3978 	 * This is used to help apply the correct atomic state while
3979 	 * we're moving away from the single pipe per plane model.
3980 	 */
3981 	plane->ref->ref = plane;
3982 	plane->ref->pipe = pipe;
3983 }
3984 
3985 /**
3986  * igt_plane_set_position:
3987  * @plane: Plane pointer for which position is to be set
3988  * @x: X coordinate
3989  * @y: Y coordinate
3990  *
3991  * This function sets a new (x,y) position for the given plane.
3992  * New position will be committed at plane commit time via drmModeSetPlane().
3993  */
igt_plane_set_position(igt_plane_t * plane,int x,int y)3994 void igt_plane_set_position(igt_plane_t *plane, int x, int y)
3995 {
3996 	igt_pipe_t *pipe = plane->pipe;
3997 	igt_display_t *display = pipe->display;
3998 
3999 	LOG(display, "%s.%d: plane_set_position(%d,%d)\n",
4000 	    kmstest_pipe_name(pipe->pipe), plane->index, x, y);
4001 
4002 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_X, x);
4003 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_Y, y);
4004 }
4005 
4006 /**
4007  * igt_plane_set_size:
4008  * @plane: plane pointer for which size to be set
4009  * @w: width
4010  * @h: height
4011  *
4012  * This function sets width and height for requested plane.
4013  * New size will be committed at plane commit time via
4014  * drmModeSetPlane().
4015  */
igt_plane_set_size(igt_plane_t * plane,int w,int h)4016 void igt_plane_set_size(igt_plane_t *plane, int w, int h)
4017 {
4018 	igt_pipe_t *pipe = plane->pipe;
4019 	igt_display_t *display = pipe->display;
4020 
4021 	LOG(display, "%s.%d: plane_set_size (%dx%d)\n",
4022 	    kmstest_pipe_name(pipe->pipe), plane->index, w, h);
4023 
4024 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_W, w);
4025 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_H, h);
4026 }
4027 
4028 /**
4029  * igt_fb_set_position:
4030  * @fb: framebuffer pointer
4031  * @plane: plane
4032  * @x: X position
4033  * @y: Y position
4034  *
4035  * This function sets position for requested framebuffer as src to plane.
4036  * New position will be committed at plane commit time via drmModeSetPlane().
4037  */
igt_fb_set_position(struct igt_fb * fb,igt_plane_t * plane,uint32_t x,uint32_t y)4038 void igt_fb_set_position(struct igt_fb *fb, igt_plane_t *plane,
4039 	uint32_t x, uint32_t y)
4040 {
4041 	igt_pipe_t *pipe = plane->pipe;
4042 	igt_display_t *display = pipe->display;
4043 
4044 	LOG(display, "%s.%d: fb_set_position(%d,%d)\n",
4045 	    kmstest_pipe_name(pipe->pipe), plane->index, x, y);
4046 
4047 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_X, IGT_FIXED(x, 0));
4048 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_Y, IGT_FIXED(y, 0));
4049 }
4050 
4051 /**
4052  * igt_fb_set_size:
4053  * @fb: framebuffer pointer
4054  * @plane: plane
4055  * @w: width
4056  * @h: height
4057  *
4058  * This function sets fetch rect size from requested framebuffer as src
4059  * to plane. New size will be committed at plane commit time via
4060  * drmModeSetPlane().
4061  */
igt_fb_set_size(struct igt_fb * fb,igt_plane_t * plane,uint32_t w,uint32_t h)4062 void igt_fb_set_size(struct igt_fb *fb, igt_plane_t *plane,
4063 	uint32_t w, uint32_t h)
4064 {
4065 	igt_pipe_t *pipe = plane->pipe;
4066 	igt_display_t *display = pipe->display;
4067 
4068 	LOG(display, "%s.%d: fb_set_size(%dx%d)\n",
4069 	    kmstest_pipe_name(pipe->pipe), plane->index, w, h);
4070 
4071 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_W, IGT_FIXED(w, 0));
4072 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_H, IGT_FIXED(h, 0));
4073 }
4074 
rotation_name(igt_rotation_t rotation)4075 static const char *rotation_name(igt_rotation_t rotation)
4076 {
4077 	switch (rotation & IGT_ROTATION_MASK) {
4078 	case IGT_ROTATION_0:
4079 		return "0°";
4080 	case IGT_ROTATION_90:
4081 		return "90°";
4082 	case IGT_ROTATION_180:
4083 		return "180°";
4084 	case IGT_ROTATION_270:
4085 		return "270°";
4086 	default:
4087 		igt_assert(0);
4088 	}
4089 }
4090 
4091 /**
4092  * igt_plane_set_rotation:
4093  * @plane: Plane pointer for which rotation is to be set
4094  * @rotation: Plane rotation value (0, 90, 180, 270)
4095  *
4096  * This function sets a new rotation for the requested @plane.
4097  * New @rotation will be committed at plane commit time via
4098  * drmModeSetPlane().
4099  */
igt_plane_set_rotation(igt_plane_t * plane,igt_rotation_t rotation)4100 void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation)
4101 {
4102 	igt_pipe_t *pipe = plane->pipe;
4103 	igt_display_t *display = pipe->display;
4104 
4105 	LOG(display, "%s.%d: plane_set_rotation(%s)\n",
4106 	    kmstest_pipe_name(pipe->pipe),
4107 	    plane->index, rotation_name(rotation));
4108 
4109 	igt_plane_set_prop_value(plane, IGT_PLANE_ROTATION, rotation);
4110 }
4111 
4112 /**
4113  * igt_pipe_request_out_fence:
4114  * @pipe: pipe which out fence will be requested for
4115  *
4116  * Marks this pipe for requesting an out fence at the next atomic commit
4117  * will contain the fd number of the out fence created by KMS.
4118  */
igt_pipe_request_out_fence(igt_pipe_t * pipe)4119 void igt_pipe_request_out_fence(igt_pipe_t *pipe)
4120 {
4121 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)&pipe->out_fence_fd);
4122 }
4123 
4124 /**
4125  * igt_wait_for_vblank_count:
4126  * @drm_fd: A drm file descriptor
4127  * @pipe: Pipe to wait_for_vblank on
4128  * @count: Number of vblanks to wait on
4129  *
4130  * Waits for a given number of vertical blank intervals
4131  */
igt_wait_for_vblank_count(int drm_fd,enum pipe pipe,int count)4132 void igt_wait_for_vblank_count(int drm_fd, enum pipe pipe, int count)
4133 {
4134 	drmVBlank wait_vbl;
4135 	uint32_t pipe_id_flag;
4136 
4137 	memset(&wait_vbl, 0, sizeof(wait_vbl));
4138 	pipe_id_flag = kmstest_get_vbl_flag(pipe);
4139 
4140 	wait_vbl.request.type = DRM_VBLANK_RELATIVE;
4141 	wait_vbl.request.type |= pipe_id_flag;
4142 	wait_vbl.request.sequence = count;
4143 
4144 	igt_assert(drmWaitVBlank(drm_fd, &wait_vbl) == 0);
4145 }
4146 
4147 /**
4148  * igt_wait_for_vblank:
4149  * @drm_fd: A drm file descriptor
4150  * @pipe: Pipe to wait_for_vblank on
4151  *
4152  * Waits for 1 vertical blank intervals
4153  */
igt_wait_for_vblank(int drm_fd,enum pipe pipe)4154 void igt_wait_for_vblank(int drm_fd, enum pipe pipe)
4155 {
4156 	igt_wait_for_vblank_count(drm_fd, pipe, 1);
4157 }
4158 
4159 /**
4160  * igt_enable_connectors:
4161  * @drm_fd: A drm file descriptor
4162  *
4163  * Force connectors to be enabled where this is known to work well. Use
4164  * #igt_reset_connectors to revert the changes.
4165  *
4166  * An exit handler is installed to ensure connectors are reset when the test
4167  * exits.
4168  */
igt_enable_connectors(int drm_fd)4169 void igt_enable_connectors(int drm_fd)
4170 {
4171 	drmModeRes *res;
4172 
4173 	res = drmModeGetResources(drm_fd);
4174 	if (!res)
4175 		return;
4176 
4177 	for (int i = 0; i < res->count_connectors; i++) {
4178 		drmModeConnector *c;
4179 
4180 		/* Do a probe. This may be the first action after booting */
4181 		c = drmModeGetConnector(drm_fd, res->connectors[i]);
4182 		if (!c) {
4183 			igt_warn("Could not read connector %u: %m\n", res->connectors[i]);
4184 			continue;
4185 		}
4186 
4187 		/* don't attempt to force connectors that are already connected
4188 		 */
4189 		if (c->connection == DRM_MODE_CONNECTED)
4190 			continue;
4191 
4192 		/* just enable VGA for now */
4193 		if (c->connector_type == DRM_MODE_CONNECTOR_VGA) {
4194 			if (!kmstest_force_connector(drm_fd, c, FORCE_CONNECTOR_ON))
4195 				igt_info("Unable to force state on %s-%d\n",
4196 					 kmstest_connector_type_str(c->connector_type),
4197 					 c->connector_type_id);
4198 		}
4199 
4200 		drmModeFreeConnector(c);
4201 	}
4202 }
4203 
4204 /**
4205  * igt_reset_connectors:
4206  *
4207  * Remove any forced state from the connectors.
4208  */
igt_reset_connectors(void)4209 void igt_reset_connectors(void)
4210 {
4211 	/* reset the connectors stored in forced_connectors, avoiding any
4212 	 * functions that are not safe to call in signal handlers */
4213 	for (int i = 0; forced_connectors[i]; i++)
4214 		igt_sysfs_set(forced_connectors_device[i],
4215 			      forced_connectors[i],
4216 			      "detect");
4217 }
4218 
4219 #if !defined(ANDROID)
4220 /**
4221  * igt_watch_hotplug:
4222  *
4223  * Begin monitoring udev for sysfs hotplug events.
4224  *
4225  * Returns: a udev monitor for detecting hotplugs on
4226  */
igt_watch_hotplug(void)4227 struct udev_monitor *igt_watch_hotplug(void)
4228 {
4229 	struct udev *udev;
4230 	struct udev_monitor *mon;
4231 	int ret, flags, fd;
4232 
4233 	udev = udev_new();
4234 	igt_assert(udev != NULL);
4235 
4236 	mon = udev_monitor_new_from_netlink(udev, "udev");
4237 	igt_assert(mon != NULL);
4238 
4239 	ret = udev_monitor_filter_add_match_subsystem_devtype(mon,
4240 							      "drm",
4241 							      "drm_minor");
4242 	igt_assert_eq(ret, 0);
4243 	ret = udev_monitor_filter_update(mon);
4244 	igt_assert_eq(ret, 0);
4245 	ret = udev_monitor_enable_receiving(mon);
4246 	igt_assert_eq(ret, 0);
4247 
4248 	/* Set the fd for udev as non blocking */
4249 	fd = udev_monitor_get_fd(mon);
4250 	flags = fcntl(fd, F_GETFL, 0);
4251 	igt_assert(flags);
4252 
4253 	flags |= O_NONBLOCK;
4254 	igt_assert_neq(fcntl(fd, F_SETFL, flags), -1);
4255 
4256 	return mon;
4257 }
4258 
event_detected(struct udev_monitor * mon,int timeout_secs,const char * property)4259 static bool event_detected(struct udev_monitor *mon, int timeout_secs,
4260 			   const char *property)
4261 {
4262 	struct udev_device *dev;
4263 	const char *hotplug_val;
4264 	struct pollfd fd = {
4265 		.fd = udev_monitor_get_fd(mon),
4266 		.events = POLLIN
4267 	};
4268 	bool hotplug_received = false;
4269 
4270 	/* Go through all of the events pending on the udev monitor. Once we
4271 	 * receive a hotplug, we continue going through the rest of the events
4272 	 * so that redundant hotplug events don't change the results of future
4273 	 * checks
4274 	 */
4275 	while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) {
4276 		dev = udev_monitor_receive_device(mon);
4277 
4278 		hotplug_val = udev_device_get_property_value(dev, property);
4279 		if (hotplug_val && atoi(hotplug_val) == 1)
4280 			hotplug_received = true;
4281 
4282 		udev_device_unref(dev);
4283 	}
4284 
4285 	return hotplug_received;
4286 }
4287 
4288 /**
4289  * igt_hotplug_detected:
4290  * @mon: A udev monitor initialized with #igt_watch_hotplug
4291  * @timeout_secs: How long to wait for a hotplug event to occur.
4292  *
4293  * Assert that a hotplug event was received since we last checked the monitor.
4294  *
4295  * Returns: true if a sysfs hotplug event was received, false if we timed out
4296  */
igt_hotplug_detected(struct udev_monitor * mon,int timeout_secs)4297 bool igt_hotplug_detected(struct udev_monitor *mon, int timeout_secs)
4298 {
4299 	return event_detected(mon, timeout_secs, "HOTPLUG");
4300 }
4301 
4302 /**
4303  * igt_lease_change_detected:
4304  * @mon: A udev monitor initialized with #igt_watch_hotplug
4305  * @timeout_secs: How long to wait for a lease change event to occur.
4306  *
4307  * Assert that a lease change event was received since we last checked the monitor.
4308  *
4309  * Returns: true if a sysfs lease change event was received, false if we timed out
4310  */
igt_lease_change_detected(struct udev_monitor * mon,int timeout_secs)4311 bool igt_lease_change_detected(struct udev_monitor *mon, int timeout_secs)
4312 {
4313 	return event_detected(mon, timeout_secs, "LEASE");
4314 }
4315 
4316 /**
4317  * igt_flush_hotplugs:
4318  * @mon: A udev monitor initialized with #igt_watch_hotplug
4319  *
4320  * Get rid of any pending hotplug events
4321  */
igt_flush_hotplugs(struct udev_monitor * mon)4322 void igt_flush_hotplugs(struct udev_monitor *mon)
4323 {
4324 	struct udev_device *dev;
4325 
4326 	while ((dev = udev_monitor_receive_device(mon)))
4327 		udev_device_unref(dev);
4328 }
4329 
4330 /**
4331  * igt_cleanup_hotplug:
4332  * @mon: A udev monitor initialized with #igt_watch_hotplug
4333  *
4334  * Cleanup the resources allocated by #igt_watch_hotplug
4335  */
igt_cleanup_hotplug(struct udev_monitor * mon)4336 void igt_cleanup_hotplug(struct udev_monitor *mon)
4337 {
4338 	struct udev *udev = udev_monitor_get_udev(mon);
4339 
4340 	udev_monitor_unref(mon);
4341 	mon = NULL;
4342 	udev_unref(udev);
4343 }
4344 #endif /*!defined(ANDROID)*/
4345 
4346 /**
4347  * kmstest_get_vbl_flag:
4348  * @pipe_id: Pipe to convert to flag representation.
4349  *
4350  * Convert a pipe id into the flag representation
4351  * expected in DRM while processing DRM_IOCTL_WAIT_VBLANK.
4352  */
kmstest_get_vbl_flag(uint32_t pipe_id)4353 uint32_t kmstest_get_vbl_flag(uint32_t pipe_id)
4354 {
4355 	if (pipe_id == 0)
4356 		return 0;
4357 	else if (pipe_id == 1)
4358 		return _DRM_VBLANK_SECONDARY;
4359 	else {
4360 		uint32_t pipe_flag = pipe_id << 1;
4361 		igt_assert(!(pipe_flag & ~DRM_VBLANK_HIGH_CRTC_MASK));
4362 		return pipe_flag;
4363 	}
4364 }
4365 
4366 static inline const uint32_t *
formats_ptr(const struct drm_format_modifier_blob * blob)4367 formats_ptr(const struct drm_format_modifier_blob *blob)
4368 {
4369 	return (const uint32_t *)((const char *)blob + blob->formats_offset);
4370 }
4371 
4372 static inline const struct drm_format_modifier *
modifiers_ptr(const struct drm_format_modifier_blob * blob)4373 modifiers_ptr(const struct drm_format_modifier_blob *blob)
4374 {
4375 	return (const struct drm_format_modifier *)((const char *)blob + blob->modifiers_offset);
4376 }
4377 
igt_count_plane_format_mod(const struct drm_format_modifier_blob * blob_data)4378 static int igt_count_plane_format_mod(const struct drm_format_modifier_blob *blob_data)
4379 {
4380 	const struct drm_format_modifier *modifiers;
4381 	int count = 0;
4382 
4383 	modifiers = modifiers_ptr(blob_data);
4384 
4385 	for (int i = 0; i < blob_data->count_modifiers; i++)
4386 		count += igt_hweight(modifiers[i].formats);
4387 
4388 	return count;
4389 }
4390 
igt_fill_plane_format_mod(igt_display_t * display,igt_plane_t * plane)4391 static void igt_fill_plane_format_mod(igt_display_t *display, igt_plane_t *plane)
4392 {
4393 	const struct drm_format_modifier_blob *blob_data;
4394 	drmModePropertyBlobPtr blob;
4395 	uint64_t blob_id;
4396 	int idx = 0;
4397 	int count;
4398 
4399 	if (!igt_plane_has_prop(plane, IGT_PLANE_IN_FORMATS)) {
4400 		drmModePlanePtr p = plane->drm_plane;
4401 
4402 		count = p->count_formats;
4403 
4404 		plane->format_mod_count = count;
4405 		plane->formats = calloc(count, sizeof(plane->formats[0]));
4406 		igt_assert(plane->formats);
4407 		plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4408 		igt_assert(plane->modifiers);
4409 
4410 		/*
4411 		 * We don't know which modifiers are
4412 		 * supported, so we'll assume linear only.
4413 		 */
4414 		for (int i = 0; i < count; i++) {
4415 			plane->formats[i] = p->formats[i];
4416 			plane->modifiers[i] = DRM_FORMAT_MOD_LINEAR;
4417 		}
4418 
4419 		return;
4420 	}
4421 
4422 	blob_id = igt_plane_get_prop(plane, IGT_PLANE_IN_FORMATS);
4423 
4424 	blob = drmModeGetPropertyBlob(display->drm_fd, blob_id);
4425 	if (!blob)
4426 		return;
4427 
4428 	blob_data = (const struct drm_format_modifier_blob *) blob->data;
4429 
4430 	count = igt_count_plane_format_mod(blob_data);
4431 	if (!count)
4432 		return;
4433 
4434 	plane->format_mod_count = count;
4435 	plane->formats = calloc(count, sizeof(plane->formats[0]));
4436 	igt_assert(plane->formats);
4437 	plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4438 	igt_assert(plane->modifiers);
4439 
4440 	for (int i = 0; i < blob_data->count_modifiers; i++) {
4441 		for (int j = 0; j < 64; j++) {
4442 			const struct drm_format_modifier *modifiers =
4443 				modifiers_ptr(blob_data);
4444 			const uint32_t *formats = formats_ptr(blob_data);
4445 
4446 			if (!(modifiers[i].formats & (1ULL << j)))
4447 				continue;
4448 
4449 			plane->formats[idx] = formats[modifiers[i].offset + j];
4450 			plane->modifiers[idx] = modifiers[i].modifier;
4451 			idx++;
4452 			igt_assert_lte(idx, plane->format_mod_count);
4453 		}
4454 	}
4455 
4456 	igt_assert_eq(idx, plane->format_mod_count);
4457 }
4458 
igt_plane_has_format_mod(igt_plane_t * plane,uint32_t format,uint64_t modifier)4459 bool igt_plane_has_format_mod(igt_plane_t *plane, uint32_t format,
4460 			      uint64_t modifier)
4461 {
4462 	int i;
4463 
4464 	for (i = 0; i < plane->format_mod_count; i++) {
4465 		if (plane->formats[i] == format &&
4466 		    plane->modifiers[i] == modifier)
4467 			return true;
4468 
4469 	}
4470 
4471 	return false;
4472 }
4473 
igt_count_display_format_mod(igt_display_t * display)4474 static int igt_count_display_format_mod(igt_display_t *display)
4475 {
4476 	enum pipe pipe;
4477 	int count = 0;
4478 
4479 	for_each_pipe(display, pipe) {
4480 		igt_plane_t *plane;
4481 
4482 		for_each_plane_on_pipe(display, pipe, plane) {
4483 			count += plane->format_mod_count;
4484 		}
4485 	}
4486 
4487 	return count;
4488 }
4489 
4490 static void
igt_add_display_format_mod(igt_display_t * display,uint32_t format,uint64_t modifier)4491 igt_add_display_format_mod(igt_display_t *display, uint32_t format,
4492 			   uint64_t modifier)
4493 {
4494 	int i;
4495 
4496 	for (i = 0; i < display->format_mod_count; i++) {
4497 		if (display->formats[i] == format &&
4498 		    display->modifiers[i] == modifier)
4499 			return;
4500 
4501 	}
4502 
4503 	display->formats[i] = format;
4504 	display->modifiers[i] = modifier;
4505 	display->format_mod_count++;
4506 }
4507 
igt_fill_display_format_mod(igt_display_t * display)4508 static void igt_fill_display_format_mod(igt_display_t *display)
4509 {
4510 	int count = igt_count_display_format_mod(display);
4511 	enum pipe pipe;
4512 
4513 	if (!count)
4514 		return;
4515 
4516 	display->formats = calloc(count, sizeof(display->formats[0]));
4517 	igt_assert(display->formats);
4518 	display->modifiers = calloc(count, sizeof(display->modifiers[0]));
4519 	igt_assert(display->modifiers);
4520 
4521 	for_each_pipe(display, pipe) {
4522 		igt_plane_t *plane;
4523 
4524 		for_each_plane_on_pipe(display, pipe, plane) {
4525 			for (int i = 0; i < plane->format_mod_count; i++) {
4526 				igt_add_display_format_mod(display,
4527 							   plane->formats[i],
4528 							   plane->modifiers[i]);
4529 				igt_assert_lte(display->format_mod_count, count);
4530 			}
4531 		}
4532 	}
4533 }
4534 
igt_display_has_format_mod(igt_display_t * display,uint32_t format,uint64_t modifier)4535 bool igt_display_has_format_mod(igt_display_t *display, uint32_t format,
4536 				uint64_t modifier)
4537 {
4538 	int i;
4539 
4540 	for (i = 0; i < display->format_mod_count; i++) {
4541 		if (display->formats[i] == format &&
4542 		    display->modifiers[i] == modifier)
4543 			return true;
4544 
4545 	}
4546 
4547 	return false;
4548 }
4549