• 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 		primary == igt_pipe_get_plane_type(primary->pipe, DRM_PLANE_TYPE_PRIMARY)))
2809 		return 0;
2810 
2811 	crtc_id = pipe->crtc_id;
2812 	fb_id = output ? igt_plane_get_fb_id(primary) : 0;
2813 	if (fb_id)
2814 		mode = igt_output_get_mode(output);
2815 	else
2816 		mode = NULL;
2817 
2818 	if (fb_id) {
2819 		uint32_t src_x = primary->values[IGT_PLANE_SRC_X] >> 16;
2820 		uint32_t src_y = primary->values[IGT_PLANE_SRC_Y] >> 16;
2821 
2822 		LOG(display,
2823 		    "%s: SetCrtc pipe %s, fb %u, src (%d, %d), "
2824 		    "mode %dx%d\n",
2825 		    igt_output_name(output),
2826 		    kmstest_pipe_name(pipe->pipe),
2827 		    fb_id,
2828 		    src_x, src_y,
2829 		    mode->hdisplay, mode->vdisplay);
2830 
2831 		ret = drmModeSetCrtc(display->drm_fd,
2832 				     crtc_id,
2833 				     fb_id,
2834 				     src_x, src_y,
2835 				     &output->id,
2836 				     1,
2837 				     mode);
2838 	} else {
2839 		LOG(display,
2840 		    "SetCrtc pipe %s, disabling\n",
2841 		    kmstest_pipe_name(pipe->pipe));
2842 
2843 		ret = drmModeSetCrtc(display->drm_fd,
2844 				     crtc_id,
2845 				     fb_id,
2846 				     0, 0, /* x, y */
2847 				     NULL, /* connectors */
2848 				     0,    /* n_connectors */
2849 				     NULL  /* mode */);
2850 	}
2851 
2852 	CHECK_RETURN(ret, fail_on_error);
2853 
2854 	return 0;
2855 }
2856 
igt_plane_fixup_rotation(igt_plane_t * plane,igt_pipe_t * pipe)2857 static int igt_plane_fixup_rotation(igt_plane_t *plane,
2858 				    igt_pipe_t *pipe)
2859 {
2860 	int ret;
2861 
2862 	if (!igt_plane_has_prop(plane, IGT_PLANE_ROTATION))
2863 		return 0;
2864 
2865 	LOG(pipe->display, "Fixing up initial rotation pipe %s, plane %d\n",
2866 	    kmstest_pipe_name(pipe->pipe), plane->index);
2867 
2868 	/* First try the easy case, can we change rotation without problems? */
2869 	ret = igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2870 				     plane->values[IGT_PLANE_ROTATION]);
2871 	if (!ret)
2872 		return 0;
2873 
2874 	/* Disable the plane, while we tinker with rotation */
2875 	ret = drmModeSetPlane(pipe->display->drm_fd,
2876 			      plane->drm_plane->plane_id,
2877 			      pipe->crtc_id, 0, /* fb_id */
2878 			      0, /* flags */
2879 			      0, 0, 0, 0, /* crtc_x, crtc_y, crtc_w, crtc_h */
2880 			      IGT_FIXED(0,0), IGT_FIXED(0,0), /* src_x, src_y */
2881 			      IGT_FIXED(0,0), IGT_FIXED(0,0)); /* src_w, src_h */
2882 
2883 	if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY)
2884 		return ret;
2885 
2886 	/* For primary plane, fall back to disabling the crtc. */
2887 	if (ret) {
2888 		ret = drmModeSetCrtc(pipe->display->drm_fd,
2889 				     pipe->crtc_id, 0, 0, 0, NULL, 0, NULL);
2890 
2891 		if (ret)
2892 			return ret;
2893 	}
2894 
2895 	/* and finally, set rotation property. */
2896 	return igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2897 				      plane->values[IGT_PLANE_ROTATION]);
2898 }
2899 
2900 /*
2901  * Commit position and fb changes to a plane.  The value of @s will determine
2902  * which API is used to do the programming.
2903  */
igt_plane_commit(igt_plane_t * plane,igt_pipe_t * pipe,enum igt_commit_style s,bool fail_on_error)2904 static int igt_plane_commit(igt_plane_t *plane,
2905 			    igt_pipe_t *pipe,
2906 			    enum igt_commit_style s,
2907 			    bool fail_on_error)
2908 {
2909 	if (pipe->display->first_commit || (s == COMMIT_UNIVERSAL &&
2910 	     igt_plane_is_prop_changed(plane, IGT_PLANE_ROTATION))) {
2911 		int ret;
2912 
2913 		ret = igt_plane_fixup_rotation(plane, pipe);
2914 		CHECK_RETURN(ret, fail_on_error);
2915 	}
2916 
2917 	if (plane->type == DRM_PLANE_TYPE_CURSOR && s == COMMIT_LEGACY) {
2918 		return igt_cursor_commit_legacy(plane, pipe, fail_on_error);
2919 	} else if (plane->type == DRM_PLANE_TYPE_PRIMARY && s == COMMIT_LEGACY &&
2920 		plane == igt_pipe_get_plane_type(plane->pipe, DRM_PLANE_TYPE_PRIMARY)) {
2921 		return igt_primary_plane_commit_legacy(plane, pipe,
2922 						       fail_on_error);
2923 	} else {
2924 		return igt_drm_plane_commit(plane, pipe, fail_on_error);
2925 	}
2926 }
2927 
is_atomic_prop(enum igt_atomic_crtc_properties prop)2928 static bool is_atomic_prop(enum igt_atomic_crtc_properties prop)
2929 {
2930        if (prop == IGT_CRTC_MODE_ID ||
2931 	   prop == IGT_CRTC_ACTIVE ||
2932 	   prop == IGT_CRTC_OUT_FENCE_PTR)
2933 		return true;
2934 
2935 	return false;
2936 }
2937 
2938 /*
2939  * Commit all plane changes to an output.  Note that if @s is COMMIT_LEGACY,
2940  * enabling/disabling the primary plane will also enable/disable the CRTC.
2941  *
2942  * If @fail_on_error is true, any failure to commit plane state will lead
2943  * to subtest failure in the specific function where the failure occurs.
2944  * Otherwise, the first error code encountered will be returned and no
2945  * further programming will take place, which may result in some changes
2946  * taking effect and others not taking effect.
2947  */
igt_pipe_commit(igt_pipe_t * pipe,enum igt_commit_style s,bool fail_on_error)2948 static int igt_pipe_commit(igt_pipe_t *pipe,
2949 			   enum igt_commit_style s,
2950 			   bool fail_on_error)
2951 {
2952 	int i;
2953 	int ret;
2954 
2955 	for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
2956 		if (igt_pipe_obj_is_prop_changed(pipe, i) &&
2957 		    !is_atomic_prop(i)) {
2958 			igt_assert(pipe->props[i]);
2959 
2960 			ret = drmModeObjectSetProperty(pipe->display->drm_fd,
2961 				pipe->crtc_id, DRM_MODE_OBJECT_CRTC,
2962 				pipe->props[i], pipe->values[i]);
2963 
2964 			CHECK_RETURN(ret, fail_on_error);
2965 		}
2966 
2967 	for (i = 0; i < pipe->n_planes; i++) {
2968 		igt_plane_t *plane = &pipe->planes[i];
2969 
2970 		/* skip planes that are handled by another pipe */
2971 		if (plane->ref->pipe != pipe)
2972 			continue;
2973 
2974 		ret = igt_plane_commit(plane, pipe, s, fail_on_error);
2975 		CHECK_RETURN(ret, fail_on_error);
2976 	}
2977 
2978 	return 0;
2979 }
2980 
igt_output_commit(igt_output_t * output,enum igt_commit_style s,bool fail_on_error)2981 static int igt_output_commit(igt_output_t *output,
2982 			     enum igt_commit_style s,
2983 			     bool fail_on_error)
2984 {
2985 	int i, ret;
2986 
2987 	for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
2988 		if (!igt_output_is_prop_changed(output, i))
2989 			continue;
2990 
2991 		/* CRTC_ID is set by calling drmModeSetCrtc in the legacy path. */
2992 		if (i == IGT_CONNECTOR_CRTC_ID)
2993 			continue;
2994 
2995 		igt_assert(output->props[i]);
2996 
2997 		if (s == COMMIT_LEGACY)
2998 			ret = drmModeConnectorSetProperty(output->display->drm_fd, output->id,
2999 							  output->props[i], output->values[i]);
3000 		else
3001 			ret = drmModeObjectSetProperty(output->display->drm_fd, output->id,
3002 						       DRM_MODE_OBJECT_CONNECTOR,
3003 						       output->props[i], output->values[i]);
3004 
3005 		CHECK_RETURN(ret, fail_on_error);
3006 	}
3007 
3008 	return 0;
3009 }
3010 
igt_mode_object_get_prop(igt_display_t * display,uint32_t object_type,uint32_t object_id,uint32_t prop)3011 static uint64_t igt_mode_object_get_prop(igt_display_t *display,
3012 					 uint32_t object_type,
3013 					 uint32_t object_id,
3014 					 uint32_t prop)
3015 {
3016 	drmModeObjectPropertiesPtr proplist;
3017 	bool found = false;
3018 	int i;
3019 	uint64_t ret;
3020 
3021 	proplist = drmModeObjectGetProperties(display->drm_fd, object_id, object_type);
3022 	for (i = 0; i < proplist->count_props; i++) {
3023 		if (proplist->props[i] != prop)
3024 			continue;
3025 
3026 		found = true;
3027 		break;
3028 	}
3029 
3030 	igt_assert(found);
3031 
3032 	ret = proplist->prop_values[i];
3033 
3034 	drmModeFreeObjectProperties(proplist);
3035 	return ret;
3036 }
3037 
3038 /**
3039  * igt_plane_get_prop:
3040  * @plane: Target plane.
3041  * @prop: Property to check.
3042  *
3043  * Return current value on a plane for a given property.
3044  *
3045  * Returns: The value the property is set to, if this
3046  * is a blob, the blob id is returned. This can be passed
3047  * to drmModeGetPropertyBlob() to get the contents of the blob.
3048  */
igt_plane_get_prop(igt_plane_t * plane,enum igt_atomic_plane_properties prop)3049 uint64_t igt_plane_get_prop(igt_plane_t *plane, enum igt_atomic_plane_properties prop)
3050 {
3051 	igt_assert(igt_plane_has_prop(plane, prop));
3052 
3053 	return igt_mode_object_get_prop(plane->pipe->display, DRM_MODE_OBJECT_PLANE,
3054 					plane->drm_plane->plane_id, plane->props[prop]);
3055 }
3056 
igt_mode_object_get_prop_enum_value(int drm_fd,uint32_t id,const char * str,uint64_t * val)3057 static bool igt_mode_object_get_prop_enum_value(int drm_fd, uint32_t id, const char *str, uint64_t *val)
3058 {
3059 	drmModePropertyPtr prop = drmModeGetProperty(drm_fd, id);
3060 	int i;
3061 
3062 	igt_assert(id);
3063 	igt_assert(prop);
3064 
3065 	for (i = 0; i < prop->count_enums; i++)
3066 		if (!strcmp(str, prop->enums[i].name)) {
3067 			*val = prop->enums[i].value;
3068 			drmModeFreeProperty(prop);
3069 			return true;
3070 		}
3071 
3072 	return false;
3073 }
3074 
igt_plane_try_prop_enum(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const char * val)3075 bool igt_plane_try_prop_enum(igt_plane_t *plane,
3076 			     enum igt_atomic_plane_properties prop,
3077 			     const char *val)
3078 {
3079 	igt_display_t *display = plane->pipe->display;
3080 	uint64_t uval;
3081 
3082 	igt_assert(plane->props[prop]);
3083 
3084 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3085 						 plane->props[prop], val, &uval))
3086 		return false;
3087 
3088 	igt_plane_set_prop_value(plane, prop, uval);
3089 	return true;
3090 }
3091 
igt_plane_set_prop_enum(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const char * val)3092 void igt_plane_set_prop_enum(igt_plane_t *plane,
3093 			     enum igt_atomic_plane_properties prop,
3094 			     const char *val)
3095 {
3096 	igt_assert(igt_plane_try_prop_enum(plane, prop, val));
3097 }
3098 
3099 /**
3100  * igt_plane_replace_prop_blob:
3101  * @plane: plane to set property on.
3102  * @prop: property for which the blob will be replaced.
3103  * @ptr: Pointer to contents for the property.
3104  * @length: Length of contents.
3105  *
3106  * This function will destroy the old property blob for the given property,
3107  * and will create a new property blob with the values passed to this function.
3108  *
3109  * The new property blob will be committed when you call igt_display_commit(),
3110  * igt_display_commit2() or igt_display_commit_atomic().
3111  */
3112 void
igt_plane_replace_prop_blob(igt_plane_t * plane,enum igt_atomic_plane_properties prop,const void * ptr,size_t length)3113 igt_plane_replace_prop_blob(igt_plane_t *plane, enum igt_atomic_plane_properties prop, const void *ptr, size_t length)
3114 {
3115 	igt_display_t *display = plane->pipe->display;
3116 	uint64_t *blob = &plane->values[prop];
3117 	uint32_t blob_id = 0;
3118 
3119 	if (*blob != 0)
3120 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3121 						      *blob) == 0);
3122 
3123 	if (length > 0)
3124 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3125 						     ptr, length, &blob_id) == 0);
3126 
3127 	*blob = blob_id;
3128 	igt_plane_set_prop_changed(plane, prop);
3129 }
3130 
3131 /**
3132  * igt_output_get_prop:
3133  * @output: Target output.
3134  * @prop: Property to return.
3135  *
3136  * Return current value on an output for a given property.
3137  *
3138  * Returns: The value the property is set to, if this
3139  * is a blob, the blob id is returned. This can be passed
3140  * to drmModeGetPropertyBlob() to get the contents of the blob.
3141  */
igt_output_get_prop(igt_output_t * output,enum igt_atomic_connector_properties prop)3142 uint64_t igt_output_get_prop(igt_output_t *output, enum igt_atomic_connector_properties prop)
3143 {
3144 	igt_assert(igt_output_has_prop(output, prop));
3145 
3146 	return igt_mode_object_get_prop(output->display, DRM_MODE_OBJECT_CONNECTOR,
3147 					output->id, output->props[prop]);
3148 }
3149 
igt_output_try_prop_enum(igt_output_t * output,enum igt_atomic_connector_properties prop,const char * val)3150 bool igt_output_try_prop_enum(igt_output_t *output,
3151 			      enum igt_atomic_connector_properties prop,
3152 			      const char *val)
3153 {
3154 	igt_display_t *display = output->display;
3155 	uint64_t uval;
3156 
3157 	igt_assert(output->props[prop]);
3158 
3159 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3160 						 output->props[prop], val, &uval))
3161 		return false;
3162 
3163 	igt_output_set_prop_value(output, prop, uval);
3164 	return true;
3165 }
3166 
igt_output_set_prop_enum(igt_output_t * output,enum igt_atomic_connector_properties prop,const char * val)3167 void igt_output_set_prop_enum(igt_output_t *output,
3168 			      enum igt_atomic_connector_properties prop,
3169 			      const char *val)
3170 {
3171 	igt_assert(igt_output_try_prop_enum(output, prop, val));
3172 }
3173 
3174 /**
3175  * igt_output_replace_prop_blob:
3176  * @output: output to set property on.
3177  * @prop: property for which the blob will be replaced.
3178  * @ptr: Pointer to contents for the property.
3179  * @length: Length of contents.
3180  *
3181  * This function will destroy the old property blob for the given property,
3182  * and will create a new property blob with the values passed to this function.
3183  *
3184  * The new property blob will be committed when you call igt_display_commit(),
3185  * igt_display_commit2() or igt_display_commit_atomic().
3186  */
3187 void
igt_output_replace_prop_blob(igt_output_t * output,enum igt_atomic_connector_properties prop,const void * ptr,size_t length)3188 igt_output_replace_prop_blob(igt_output_t *output, enum igt_atomic_connector_properties prop, const void *ptr, size_t length)
3189 {
3190 	igt_display_t *display = output->display;
3191 	uint64_t *blob = &output->values[prop];
3192 	uint32_t blob_id = 0;
3193 
3194 	if (*blob != 0)
3195 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3196 						      *blob) == 0);
3197 
3198 	if (length > 0)
3199 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3200 						     ptr, length, &blob_id) == 0);
3201 
3202 	*blob = blob_id;
3203 	igt_output_set_prop_changed(output, prop);
3204 }
3205 
3206 /**
3207  * igt_pipe_obj_get_prop:
3208  * @pipe: Target pipe.
3209  * @prop: Property to return.
3210  *
3211  * Return current value on a pipe for a given property.
3212  *
3213  * Returns: The value the property is set to, if this
3214  * is a blob, the blob id is returned. This can be passed
3215  * to drmModeGetPropertyBlob() to get the contents of the blob.
3216  */
igt_pipe_obj_get_prop(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop)3217 uint64_t igt_pipe_obj_get_prop(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
3218 {
3219 	igt_assert(igt_pipe_obj_has_prop(pipe, prop));
3220 
3221 	return igt_mode_object_get_prop(pipe->display, DRM_MODE_OBJECT_CRTC,
3222 					pipe->crtc_id, pipe->props[prop]);
3223 }
3224 
igt_pipe_obj_try_prop_enum(igt_pipe_t * pipe_obj,enum igt_atomic_crtc_properties prop,const char * val)3225 bool igt_pipe_obj_try_prop_enum(igt_pipe_t *pipe_obj,
3226 				enum igt_atomic_crtc_properties prop,
3227 				const char *val)
3228 {
3229 	igt_display_t *display = pipe_obj->display;
3230 	uint64_t uval;
3231 
3232 	igt_assert(pipe_obj->props[prop]);
3233 
3234 	if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3235 						 pipe_obj->props[prop], val, &uval))
3236 		return false;
3237 
3238 	igt_pipe_obj_set_prop_value(pipe_obj, prop, uval);
3239 	return true;
3240 }
3241 
igt_pipe_obj_set_prop_enum(igt_pipe_t * pipe_obj,enum igt_atomic_crtc_properties prop,const char * val)3242 void igt_pipe_obj_set_prop_enum(igt_pipe_t *pipe_obj,
3243 				enum igt_atomic_crtc_properties prop,
3244 				const char *val)
3245 {
3246 	igt_assert(igt_pipe_obj_try_prop_enum(pipe_obj, prop, val));
3247 }
3248 
3249 /**
3250  * igt_pipe_obj_replace_prop_blob:
3251  * @pipe: pipe to set property on.
3252  * @prop: property for which the blob will be replaced.
3253  * @ptr: Pointer to contents for the property.
3254  * @length: Length of contents.
3255  *
3256  * This function will destroy the old property blob for the given property,
3257  * and will create a new property blob with the values passed to this function.
3258  *
3259  * The new property blob will be committed when you call igt_display_commit(),
3260  * igt_display_commit2() or igt_display_commit_atomic().
3261  *
3262  * Please use igt_output_override_mode() if you want to set #IGT_CRTC_MODE_ID,
3263  * it works better with legacy commit.
3264  */
3265 void
igt_pipe_obj_replace_prop_blob(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop,const void * ptr,size_t length)3266 igt_pipe_obj_replace_prop_blob(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop, const void *ptr, size_t length)
3267 {
3268 	igt_display_t *display = pipe->display;
3269 	uint64_t *blob = &pipe->values[prop];
3270 	uint32_t blob_id = 0;
3271 
3272 	if (*blob != 0)
3273 		igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3274 						      *blob) == 0);
3275 
3276 	if (length > 0)
3277 		igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3278 						     ptr, length, &blob_id) == 0);
3279 
3280 	*blob = blob_id;
3281 	igt_pipe_obj_set_prop_changed(pipe, prop);
3282 }
3283 
3284 /*
3285  * Add crtc property changes to the atomic property set
3286  */
igt_atomic_prepare_crtc_commit(igt_pipe_t * pipe_obj,drmModeAtomicReq * req)3287 static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
3288 {
3289 	int i;
3290 
3291 	for (i = 0; i < IGT_NUM_CRTC_PROPS; i++) {
3292 		if (!igt_pipe_obj_is_prop_changed(pipe_obj, i))
3293 			continue;
3294 
3295 		igt_debug("Pipe %s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3296 			kmstest_pipe_name(pipe_obj->pipe), igt_crtc_prop_names[i],
3297 			pipe_obj->values[i], pipe_obj->values[i]);
3298 
3299 		igt_assert_lt(0, drmModeAtomicAddProperty(req, pipe_obj->crtc_id, pipe_obj->props[i], pipe_obj->values[i]));
3300 	}
3301 
3302 	if (pipe_obj->out_fence_fd != -1) {
3303 		close(pipe_obj->out_fence_fd);
3304 		pipe_obj->out_fence_fd = -1;
3305 	}
3306 }
3307 
3308 /*
3309  * Add connector property changes to the atomic property set
3310  */
igt_atomic_prepare_connector_commit(igt_output_t * output,drmModeAtomicReq * req)3311 static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
3312 {
3313 
3314 	int i;
3315 
3316 	for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
3317 		if (!igt_output_is_prop_changed(output, i))
3318 			continue;
3319 
3320 		/* it's an error to try an unsupported feature */
3321 		igt_assert(output->props[i]);
3322 
3323 		igt_debug("%s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3324 			  igt_output_name(output), igt_connector_prop_names[i],
3325 			  output->values[i], output->values[i]);
3326 
3327 		igt_assert_lt(0, drmModeAtomicAddProperty(req,
3328 					  output->config.connector->connector_id,
3329 					  output->props[i],
3330 					  output->values[i]));
3331 	}
3332 }
3333 
3334 /*
3335  * Commit all the changes of all the planes,crtcs, connectors
3336  * atomically using drmModeAtomicCommit()
3337  */
igt_atomic_commit(igt_display_t * display,uint32_t flags,void * user_data)3338 static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_data)
3339 {
3340 
3341 	int ret = 0, i;
3342 	enum pipe pipe;
3343 	drmModeAtomicReq *req;
3344 	igt_output_t *output;
3345 
3346 	if (display->is_atomic != 1)
3347 		return -1;
3348 	req = drmModeAtomicAlloc();
3349 
3350 	for_each_pipe(display, pipe) {
3351 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
3352 		igt_plane_t *plane;
3353 
3354 		/*
3355 		 * Add CRTC Properties to the property set
3356 		 */
3357 		if (pipe_obj->changed)
3358 			igt_atomic_prepare_crtc_commit(pipe_obj, req);
3359 
3360 		for_each_plane_on_pipe(display, pipe, plane) {
3361 			/* skip planes that are handled by another pipe */
3362 			if (plane->ref->pipe != pipe_obj)
3363 				continue;
3364 
3365 			if (plane->changed)
3366 				igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
3367 		}
3368 
3369 	}
3370 
3371 	for (i = 0; i < display->n_outputs; i++) {
3372 		output = &display->outputs[i];
3373 
3374 		if (!output->config.connector || !output->changed)
3375 			continue;
3376 
3377 		LOG(display, "%s: preparing atomic, pipe: %s\n",
3378 		    igt_output_name(output),
3379 		    kmstest_pipe_name(output->config.pipe));
3380 
3381 		igt_atomic_prepare_connector_commit(output, req);
3382 	}
3383 
3384 	ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data);
3385 
3386 	drmModeAtomicFree(req);
3387 	return ret;
3388 
3389 }
3390 
3391 static void
display_commit_changed(igt_display_t * display,enum igt_commit_style s)3392 display_commit_changed(igt_display_t *display, enum igt_commit_style s)
3393 {
3394 	int i;
3395 	enum pipe pipe;
3396 
3397 	for_each_pipe(display, pipe) {
3398 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
3399 		igt_plane_t *plane;
3400 
3401 		if (s == COMMIT_ATOMIC) {
3402 			if (igt_pipe_obj_is_prop_changed(pipe_obj, IGT_CRTC_OUT_FENCE_PTR))
3403 				igt_assert(pipe_obj->out_fence_fd >= 0);
3404 
3405 			pipe_obj->values[IGT_CRTC_OUT_FENCE_PTR] = 0;
3406 			pipe_obj->changed = 0;
3407 		} else {
3408 			for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
3409 				if (!is_atomic_prop(i))
3410 					igt_pipe_obj_clear_prop_changed(pipe_obj, i);
3411 
3412 			if (s != COMMIT_UNIVERSAL) {
3413 				igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3414 				igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_ACTIVE);
3415 			}
3416 		}
3417 
3418 		for_each_plane_on_pipe(display, pipe, plane) {
3419 			if (s == COMMIT_ATOMIC) {
3420 				int fd;
3421 				plane->changed = 0;
3422 
3423 				fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3424 				if (fd != -1)
3425 					close(fd);
3426 
3427 				/* reset fence_fd to prevent it from being set for the next commit */
3428 				plane->values[IGT_PLANE_IN_FENCE_FD] = -1;
3429 			} else {
3430 				plane->changed &= ~IGT_PLANE_COORD_CHANGED_MASK;
3431 
3432 				igt_plane_clear_prop_changed(plane, IGT_PLANE_CRTC_ID);
3433 				igt_plane_clear_prop_changed(plane, IGT_PLANE_FB_ID);
3434 
3435 				if (s != COMMIT_LEGACY ||
3436 				    !(plane->type == DRM_PLANE_TYPE_PRIMARY ||
3437 				      plane->type == DRM_PLANE_TYPE_CURSOR))
3438 					plane->changed &= ~LEGACY_PLANE_COMMIT_MASK;
3439 
3440 				if (display->first_commit)
3441 					igt_plane_clear_prop_changed(plane, IGT_PLANE_ROTATION);
3442 			}
3443 		}
3444 	}
3445 
3446 	for (i = 0; i < display->n_outputs; i++) {
3447 		igt_output_t *output = &display->outputs[i];
3448 
3449 		if (s != COMMIT_UNIVERSAL)
3450 			output->changed = 0;
3451 		else
3452 			/* no modeset in universal commit, no change to crtc. */
3453 			output->changed &= 1 << IGT_CONNECTOR_CRTC_ID;
3454 	}
3455 
3456 	if (display->first_commit) {
3457 		igt_reset_fifo_underrun_reporting(display->drm_fd);
3458 
3459 		igt_display_drop_events(display);
3460 
3461 		display->first_commit = false;
3462 	}
3463 }
3464 
3465 /*
3466  * Commit all plane changes across all outputs of the display.
3467  *
3468  * If @fail_on_error is true, any failure to commit plane state will lead
3469  * to subtest failure in the specific function where the failure occurs.
3470  * Otherwise, the first error code encountered will be returned and no
3471  * further programming will take place, which may result in some changes
3472  * taking effect and others not taking effect.
3473  */
do_display_commit(igt_display_t * display,enum igt_commit_style s,bool fail_on_error)3474 static int do_display_commit(igt_display_t *display,
3475 			     enum igt_commit_style s,
3476 			     bool fail_on_error)
3477 {
3478 	int i, ret = 0;
3479 	enum pipe pipe;
3480 	LOG_INDENT(display, "commit");
3481 
3482 	/* someone managed to bypass igt_display_require, catch them */
3483 	assert(display->n_pipes && display->n_outputs);
3484 
3485 	igt_display_refresh(display);
3486 
3487 	if (s == COMMIT_ATOMIC) {
3488 		ret = igt_atomic_commit(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
3489 	} else {
3490 		for_each_pipe(display, pipe) {
3491 			igt_pipe_t *pipe_obj = &display->pipes[pipe];
3492 
3493 			ret = igt_pipe_commit(pipe_obj, s, fail_on_error);
3494 			if (ret)
3495 				break;
3496 		}
3497 
3498 		for (i = 0; !ret && i < display->n_outputs; i++)
3499 			ret = igt_output_commit(&display->outputs[i], s, fail_on_error);
3500 	}
3501 
3502 	LOG_UNINDENT(display);
3503 	CHECK_RETURN(ret, fail_on_error);
3504 
3505 	display_commit_changed(display, s);
3506 
3507 	igt_debug_wait_for_keypress("modeset");
3508 
3509 	return 0;
3510 }
3511 
3512 /**
3513  * igt_display_try_commit_atomic:
3514  * @display: #igt_display_t to commit.
3515  * @flags: Flags passed to drmModeAtomicCommit.
3516  * @user_data: User defined pointer passed to drmModeAtomicCommit.
3517  *
3518  * This function is similar to #igt_display_try_commit2, but is
3519  * used when you want to pass different flags to the actual commit.
3520  *
3521  * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3522  * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3523  * or DRM_MODE_ATOMIC_TEST_ONLY.
3524  *
3525  * @user_data is returned in the event if you pass
3526  * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3527  *
3528  * This function will return an error if commit fails, instead of
3529  * aborting the test.
3530  */
igt_display_try_commit_atomic(igt_display_t * display,uint32_t flags,void * user_data)3531 int igt_display_try_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3532 {
3533 	int ret;
3534 
3535 	/* someone managed to bypass igt_display_require, catch them */
3536 	assert(display->n_pipes && display->n_outputs);
3537 
3538 	LOG_INDENT(display, "commit");
3539 
3540 	igt_display_refresh(display);
3541 
3542 	ret = igt_atomic_commit(display, flags, user_data);
3543 
3544 	LOG_UNINDENT(display);
3545 
3546 	if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))
3547 		return ret;
3548 
3549 	if (display->first_commit)
3550 		igt_fail_on_f(flags & (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK),
3551 			      "First commit has to drop all stale events\n");
3552 
3553 	display_commit_changed(display, COMMIT_ATOMIC);
3554 
3555 	igt_debug_wait_for_keypress("modeset");
3556 
3557 	return 0;
3558 }
3559 
3560 /**
3561  * igt_display_commit_atomic:
3562  * @display: #igt_display_t to commit.
3563  * @flags: Flags passed to drmModeAtomicCommit.
3564  * @user_data: User defined pointer passed to drmModeAtomicCommit.
3565  *
3566  * This function is similar to #igt_display_commit2, but is
3567  * used when you want to pass different flags to the actual commit.
3568  *
3569  * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3570  * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3571  * or DRM_MODE_ATOMIC_TEST_ONLY.
3572  *
3573  * @user_data is returned in the event if you pass
3574  * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3575  *
3576  * This function will abort the test if commit fails.
3577  */
igt_display_commit_atomic(igt_display_t * display,uint32_t flags,void * user_data)3578 void igt_display_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3579 {
3580 	int ret = igt_display_try_commit_atomic(display, flags, user_data);
3581 
3582 	igt_assert_eq(ret, 0);
3583 }
3584 
3585 /**
3586  * igt_display_commit2:
3587  * @display: DRM device handle
3588  * @s: Commit style
3589  *
3590  * Commits framebuffer and positioning changes to all planes of each display
3591  * pipe, using a specific API to perform the programming.  This function should
3592  * be used to exercise a specific driver programming API; igt_display_commit
3593  * should be used instead if the API used is unimportant to the test being run.
3594  *
3595  * This function should only be used to commit changes that are expected to
3596  * succeed, since any failure during the commit process will cause the IGT
3597  * subtest to fail.  To commit changes that are expected to fail, use
3598  * @igt_try_display_commit2 instead.
3599  *
3600  * Returns: 0 upon success.  This function will never return upon failure
3601  * since igt_fail() at lower levels will longjmp out of it.
3602  */
igt_display_commit2(igt_display_t * display,enum igt_commit_style s)3603 int igt_display_commit2(igt_display_t *display,
3604 		       enum igt_commit_style s)
3605 {
3606 	do_display_commit(display, s, true);
3607 
3608 	return 0;
3609 }
3610 
3611 /**
3612  * igt_display_try_commit2:
3613  * @display: DRM device handle
3614  * @s: Commit style
3615  *
3616  * Attempts to commit framebuffer and positioning changes to all planes of each
3617  * display pipe.  This function should be used to commit changes that are
3618  * expected to fail, so that the error code can be checked for correctness.
3619  * For changes that are expected to succeed, use @igt_display_commit instead.
3620  *
3621  * Note that in non-atomic commit styles, no display programming will be
3622  * performed after the first failure is encountered, so only some of the
3623  * operations requested by a test may have been completed.  Tests that catch
3624  * errors returned by this function should take care to restore the display to
3625  * a sane state after a failure is detected.
3626  *
3627  * Returns: 0 upon success, otherwise the error code of the first error
3628  * encountered.
3629  */
igt_display_try_commit2(igt_display_t * display,enum igt_commit_style s)3630 int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s)
3631 {
3632 	return do_display_commit(display, s, false);
3633 }
3634 
3635 /**
3636  * igt_display_commit:
3637  * @display: DRM device handle
3638  *
3639  * Commits framebuffer and positioning changes to all planes of each display
3640  * pipe.
3641  *
3642  * Returns: 0 upon success.  This function will never return upon failure
3643  * since igt_fail() at lower levels will longjmp out of it.
3644  */
igt_display_commit(igt_display_t * display)3645 int igt_display_commit(igt_display_t *display)
3646 {
3647 	return igt_display_commit2(display, COMMIT_LEGACY);
3648 }
3649 
3650 /**
3651  * igt_display_drop_events:
3652  * @display: DRM device handle
3653  *
3654  * Nonblockingly reads all current events and drops them, for highest
3655  * reliablility, call igt_display_commit2() first to flush all outstanding
3656  * events.
3657  *
3658  * This will be called on the first commit after igt_display_reset() too,
3659  * to make sure any stale events are flushed.
3660  *
3661  * Returns: Number of dropped events.
3662  */
igt_display_drop_events(igt_display_t * display)3663 int igt_display_drop_events(igt_display_t *display)
3664 {
3665 	int ret = 0;
3666 
3667 	/* Clear all events from drm fd. */
3668 	struct pollfd pfd = {
3669 		.fd = display->drm_fd,
3670 		.events = POLLIN
3671 	};
3672 
3673 	while (poll(&pfd, 1, 0) > 0) {
3674 		struct drm_event *ev;
3675 		char buf[4096];
3676 		ssize_t retval;
3677 
3678 		retval = read(display->drm_fd, &buf, sizeof(buf));
3679 		igt_assert_lt(0, retval);
3680 
3681 		for (int i = 0; i < retval; i += ev->length) {
3682 			ev = (struct drm_event *)&buf[i];
3683 
3684 			igt_info("Dropping event type %u length %u\n", ev->type, ev->length);
3685 			igt_assert(ev->length + i <= sizeof(buf));
3686 			ret++;
3687 		}
3688 	}
3689 
3690 	return ret;
3691 }
3692 
3693 /**
3694  * igt_output_name:
3695  * @output: Target output
3696  *
3697  * Returns: String representing a connector's name, e.g. "DP-1".
3698  */
igt_output_name(igt_output_t * output)3699 const char *igt_output_name(igt_output_t *output)
3700 {
3701 	return output->name;
3702 }
3703 
3704 /**
3705  * igt_output_get_mode:
3706  * @output: Target output
3707  *
3708  * Get the current mode of the given connector
3709  *
3710  * Returns: A #drmModeModeInfo struct representing the current mode
3711  */
igt_output_get_mode(igt_output_t * output)3712 drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
3713 {
3714 	if (output->use_override_mode)
3715 		return &output->override_mode;
3716 	else
3717 		return &output->config.default_mode;
3718 }
3719 
3720 /**
3721  * igt_output_override_mode:
3722  * @output: Output of which the mode will be overridden
3723  * @mode: New mode, or NULL to disable override.
3724  *
3725  * Overrides the output's mode with @mode, so that it is used instead of the
3726  * mode obtained with get connectors. Note that the mode is used without
3727  * checking if the output supports it, so this might lead to unexpected results.
3728  */
igt_output_override_mode(igt_output_t * output,const drmModeModeInfo * mode)3729 void igt_output_override_mode(igt_output_t *output, const drmModeModeInfo *mode)
3730 {
3731 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3732 
3733 	if (mode)
3734 		output->override_mode = *mode;
3735 
3736 	output->use_override_mode = !!mode;
3737 
3738 	if (pipe) {
3739 		if (output->display->is_atomic)
3740 			igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(*mode));
3741 		else
3742 			igt_pipe_obj_set_prop_changed(pipe, IGT_CRTC_MODE_ID);
3743 	}
3744 }
3745 
3746 /*
3747  * igt_output_set_pipe:
3748  * @output: Target output for which the pipe is being set to
3749  * @pipe: Display pipe to set to
3750  *
3751  * This function sets a @pipe to a specific @output connector by
3752  * setting the CRTC_ID property of the @pipe. The pipe
3753  * is only activated for all pipes except PIPE_NONE.
3754  */
igt_output_set_pipe(igt_output_t * output,enum pipe pipe)3755 void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
3756 {
3757 	igt_display_t *display = output->display;
3758 	igt_pipe_t *old_pipe = NULL, *pipe_obj = NULL;;
3759 
3760 	igt_assert(output->name);
3761 
3762 	if (output->pending_pipe != PIPE_NONE)
3763 		old_pipe = igt_output_get_driving_pipe(output);
3764 
3765 	if (pipe != PIPE_NONE)
3766 		pipe_obj = &display->pipes[pipe];
3767 
3768 	LOG(display, "%s: set_pipe(%s)\n", igt_output_name(output),
3769 	    kmstest_pipe_name(pipe));
3770 	output->pending_pipe = pipe;
3771 
3772 	if (old_pipe) {
3773 		igt_output_t *old_output;
3774 
3775 		old_output = igt_pipe_get_output(old_pipe);
3776 		if (!old_output) {
3777 			if (display->is_atomic)
3778 				igt_pipe_obj_replace_prop_blob(old_pipe, IGT_CRTC_MODE_ID, NULL, 0);
3779 			else
3780 				igt_pipe_obj_set_prop_changed(old_pipe, IGT_CRTC_MODE_ID);
3781 
3782 			igt_pipe_obj_set_prop_value(old_pipe, IGT_CRTC_ACTIVE, 0);
3783 		}
3784 	}
3785 
3786 	igt_output_set_prop_value(output, IGT_CONNECTOR_CRTC_ID, pipe == PIPE_NONE ? 0 : display->pipes[pipe].crtc_id);
3787 
3788 	igt_output_refresh(output);
3789 
3790 	if (pipe_obj) {
3791 		if (display->is_atomic)
3792 			igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
3793 		else
3794 			igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3795 
3796 		igt_pipe_obj_set_prop_value(pipe_obj, IGT_CRTC_ACTIVE, 1);
3797 	}
3798 }
3799 
3800 /*
3801  * igt_pipe_refresh:
3802  * @display: a pointer to an #igt_display_t structure
3803  * @pipe: Pipe to refresh
3804  * @force: Should be set to true if mode_blob is no longer considered
3805  * to be valid, for example after doing an atomic commit during fork or closing display fd.
3806  *
3807  * Requests the pipe to be part of the state on next update.
3808  * This is useful when state may have been out of sync after
3809  * a fork, or we just want to be sure the pipe is included
3810  * in the next commit.
3811  */
igt_pipe_refresh(igt_display_t * display,enum pipe pipe,bool force)3812 void igt_pipe_refresh(igt_display_t *display, enum pipe pipe, bool force)
3813 {
3814 	igt_pipe_t *pipe_obj = &display->pipes[pipe];
3815 
3816 	if (force && display->is_atomic) {
3817 		igt_output_t *output = igt_pipe_get_output(pipe_obj);
3818 
3819 		pipe_obj->values[IGT_CRTC_MODE_ID] = 0;
3820 		if (output)
3821 			igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
3822 	} else
3823 		igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3824 }
3825 
igt_output_get_plane(igt_output_t * output,int plane_idx)3826 igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx)
3827 {
3828 	igt_pipe_t *pipe;
3829 
3830 	pipe = igt_output_get_driving_pipe(output);
3831 	igt_assert(pipe);
3832 
3833 	return igt_pipe_get_plane(pipe, plane_idx);
3834 }
3835 
3836 /**
3837  * igt_output_get_plane_type:
3838  * @output: Target output
3839  * @plane_type: Cursor, primary or an overlay plane
3840  *
3841  * Finds a valid plane type for the given @output otherwise
3842  * the test is skipped if the right combination of @output/@plane_type is not found
3843  *
3844  * Returns: A #igt_plane_t structure that matches the requested plane type
3845  */
igt_output_get_plane_type(igt_output_t * output,int plane_type)3846 igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type)
3847 {
3848 	igt_pipe_t *pipe;
3849 
3850 	pipe = igt_output_get_driving_pipe(output);
3851 	igt_assert(pipe);
3852 
3853 	return igt_pipe_get_plane_type(pipe, plane_type);
3854 }
3855 
3856 /**
3857  * igt_output_count_plane_type:
3858  * @output: Target output
3859  * @plane_type: Cursor, primary or an overlay plane
3860  *
3861  * Counts the number of planes of type @plane_type for the provided @output.
3862  *
3863  * Returns: The number of planes that match the requested plane type
3864  */
igt_output_count_plane_type(igt_output_t * output,int plane_type)3865 int igt_output_count_plane_type(igt_output_t *output, int plane_type)
3866 {
3867 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3868 	igt_assert(pipe);
3869 
3870 	return igt_pipe_count_plane_type(pipe, plane_type);
3871 }
3872 
3873 /**
3874  * igt_output_get_plane_type_index:
3875  * @output: Target output
3876  * @plane_type: Cursor, primary or an overlay plane
3877  * @index: the index of the plane among planes of the same type
3878  *
3879  * Get the @index th plane of type @plane_type for the provided @output.
3880  *
3881  * Returns: The @index th plane that matches the requested plane type
3882  */
igt_output_get_plane_type_index(igt_output_t * output,int plane_type,int index)3883 igt_plane_t *igt_output_get_plane_type_index(igt_output_t *output,
3884 					     int plane_type, int index)
3885 {
3886 	igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3887 	igt_assert(pipe);
3888 
3889 	return igt_pipe_get_plane_type_index(pipe, plane_type, index);
3890 }
3891 
3892 /**
3893  * igt_plane_set_fb:
3894  * @plane: Plane
3895  * @fb: Framebuffer pointer
3896  *
3897  * Pairs a given @framebuffer to a @plane
3898  *
3899  * This function also sets a default size and position for the framebuffer
3900  * to avoid crashes on applications that ignore to set these.
3901  */
igt_plane_set_fb(igt_plane_t * plane,struct igt_fb * fb)3902 void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb)
3903 {
3904 	igt_pipe_t *pipe = plane->pipe;
3905 	igt_display_t *display = pipe->display;
3906 
3907 	LOG(display, "%s.%d: plane_set_fb(%d)\n", kmstest_pipe_name(pipe->pipe),
3908 	    plane->index, fb ? fb->fb_id : 0);
3909 
3910 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, fb ? pipe->crtc_id : 0);
3911 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, fb ? fb->fb_id : 0);
3912 
3913 	if (plane->type == DRM_PLANE_TYPE_CURSOR && fb)
3914 		plane->gem_handle = fb->gem_handle;
3915 	else
3916 		plane->gem_handle = 0;
3917 
3918 	/* hack to keep tests working that don't call igt_plane_set_size() */
3919 	if (fb) {
3920 		/* set default plane size as fb size */
3921 		igt_plane_set_size(plane, fb->width, fb->height);
3922 
3923 		/* set default src pos/size as fb size */
3924 		igt_fb_set_position(fb, plane, 0, 0);
3925 		igt_fb_set_size(fb, plane, fb->width, fb->height);
3926 
3927 		if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
3928 			igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
3929 				igt_color_encoding_to_str(fb->color_encoding));
3930 		if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
3931 			igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
3932 				igt_color_range_to_str(fb->color_range));
3933 
3934 		/* Hack to prioritize the plane on the pipe that last set fb */
3935 		igt_plane_set_pipe(plane, pipe);
3936 	} else {
3937 		igt_plane_set_size(plane, 0, 0);
3938 
3939 		/* set default src pos/size as fb size */
3940 		igt_fb_set_position(fb, plane, 0, 0);
3941 		igt_fb_set_size(fb, plane, 0, 0);
3942 	}
3943 }
3944 
3945 /**
3946  * igt_plane_set_fence_fd:
3947  * @plane: plane
3948  * @fence_fd: fence fd, disable fence_fd by setting it to -1
3949  *
3950  * This function sets a fence fd to enable a commit to wait for some event to
3951  * occur before completing.
3952  */
igt_plane_set_fence_fd(igt_plane_t * plane,int fence_fd)3953 void igt_plane_set_fence_fd(igt_plane_t *plane, int fence_fd)
3954 {
3955 	int64_t fd;
3956 
3957 	fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3958 	if (fd != -1)
3959 		close(fd);
3960 
3961 	if (fence_fd != -1) {
3962 		fd = dup(fence_fd);
3963 		igt_fail_on(fd == -1);
3964 	} else
3965 		fd = -1;
3966 
3967 	igt_plane_set_prop_value(plane, IGT_PLANE_IN_FENCE_FD, fd);
3968 }
3969 
3970 /**
3971  * igt_plane_set_pipe:
3972  * @plane: Target plane pointer
3973  * @pipe: The pipe to assign the plane to
3974  *
3975  */
igt_plane_set_pipe(igt_plane_t * plane,igt_pipe_t * pipe)3976 void igt_plane_set_pipe(igt_plane_t *plane, igt_pipe_t *pipe)
3977 {
3978 	/*
3979 	 * HACK: Point the global plane back to the local plane.
3980 	 * This is used to help apply the correct atomic state while
3981 	 * we're moving away from the single pipe per plane model.
3982 	 */
3983 	plane->ref->ref = plane;
3984 	plane->ref->pipe = pipe;
3985 }
3986 
3987 /**
3988  * igt_plane_set_position:
3989  * @plane: Plane pointer for which position is to be set
3990  * @x: X coordinate
3991  * @y: Y coordinate
3992  *
3993  * This function sets a new (x,y) position for the given plane.
3994  * New position will be committed at plane commit time via drmModeSetPlane().
3995  */
igt_plane_set_position(igt_plane_t * plane,int x,int y)3996 void igt_plane_set_position(igt_plane_t *plane, int x, int y)
3997 {
3998 	igt_pipe_t *pipe = plane->pipe;
3999 	igt_display_t *display = pipe->display;
4000 
4001 	LOG(display, "%s.%d: plane_set_position(%d,%d)\n",
4002 	    kmstest_pipe_name(pipe->pipe), plane->index, x, y);
4003 
4004 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_X, x);
4005 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_Y, y);
4006 }
4007 
4008 /**
4009  * igt_plane_set_size:
4010  * @plane: plane pointer for which size to be set
4011  * @w: width
4012  * @h: height
4013  *
4014  * This function sets width and height for requested plane.
4015  * New size will be committed at plane commit time via
4016  * drmModeSetPlane().
4017  */
igt_plane_set_size(igt_plane_t * plane,int w,int h)4018 void igt_plane_set_size(igt_plane_t *plane, int w, int h)
4019 {
4020 	igt_pipe_t *pipe = plane->pipe;
4021 	igt_display_t *display = pipe->display;
4022 
4023 	LOG(display, "%s.%d: plane_set_size (%dx%d)\n",
4024 	    kmstest_pipe_name(pipe->pipe), plane->index, w, h);
4025 
4026 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_W, w);
4027 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_H, h);
4028 }
4029 
4030 /**
4031  * igt_fb_set_position:
4032  * @fb: framebuffer pointer
4033  * @plane: plane
4034  * @x: X position
4035  * @y: Y position
4036  *
4037  * This function sets position for requested framebuffer as src to plane.
4038  * New position will be committed at plane commit time via drmModeSetPlane().
4039  */
igt_fb_set_position(struct igt_fb * fb,igt_plane_t * plane,uint32_t x,uint32_t y)4040 void igt_fb_set_position(struct igt_fb *fb, igt_plane_t *plane,
4041 	uint32_t x, uint32_t y)
4042 {
4043 	igt_pipe_t *pipe = plane->pipe;
4044 	igt_display_t *display = pipe->display;
4045 
4046 	LOG(display, "%s.%d: fb_set_position(%d,%d)\n",
4047 	    kmstest_pipe_name(pipe->pipe), plane->index, x, y);
4048 
4049 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_X, IGT_FIXED(x, 0));
4050 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_Y, IGT_FIXED(y, 0));
4051 }
4052 
4053 /**
4054  * igt_fb_set_size:
4055  * @fb: framebuffer pointer
4056  * @plane: plane
4057  * @w: width
4058  * @h: height
4059  *
4060  * This function sets fetch rect size from requested framebuffer as src
4061  * to plane. New size will be committed at plane commit time via
4062  * drmModeSetPlane().
4063  */
igt_fb_set_size(struct igt_fb * fb,igt_plane_t * plane,uint32_t w,uint32_t h)4064 void igt_fb_set_size(struct igt_fb *fb, igt_plane_t *plane,
4065 	uint32_t w, uint32_t h)
4066 {
4067 	igt_pipe_t *pipe = plane->pipe;
4068 	igt_display_t *display = pipe->display;
4069 
4070 	LOG(display, "%s.%d: fb_set_size(%dx%d)\n",
4071 	    kmstest_pipe_name(pipe->pipe), plane->index, w, h);
4072 
4073 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_W, IGT_FIXED(w, 0));
4074 	igt_plane_set_prop_value(plane, IGT_PLANE_SRC_H, IGT_FIXED(h, 0));
4075 }
4076 
rotation_name(igt_rotation_t rotation)4077 static const char *rotation_name(igt_rotation_t rotation)
4078 {
4079 	switch (rotation & IGT_ROTATION_MASK) {
4080 	case IGT_ROTATION_0:
4081 		return "0°";
4082 	case IGT_ROTATION_90:
4083 		return "90°";
4084 	case IGT_ROTATION_180:
4085 		return "180°";
4086 	case IGT_ROTATION_270:
4087 		return "270°";
4088 	default:
4089 		igt_assert(0);
4090 	}
4091 }
4092 
4093 /**
4094  * igt_plane_set_rotation:
4095  * @plane: Plane pointer for which rotation is to be set
4096  * @rotation: Plane rotation value (0, 90, 180, 270)
4097  *
4098  * This function sets a new rotation for the requested @plane.
4099  * New @rotation will be committed at plane commit time via
4100  * drmModeSetPlane().
4101  */
igt_plane_set_rotation(igt_plane_t * plane,igt_rotation_t rotation)4102 void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation)
4103 {
4104 	igt_pipe_t *pipe = plane->pipe;
4105 	igt_display_t *display = pipe->display;
4106 
4107 	LOG(display, "%s.%d: plane_set_rotation(%s)\n",
4108 	    kmstest_pipe_name(pipe->pipe),
4109 	    plane->index, rotation_name(rotation));
4110 
4111 	igt_plane_set_prop_value(plane, IGT_PLANE_ROTATION, rotation);
4112 }
4113 
4114 /**
4115  * igt_pipe_request_out_fence:
4116  * @pipe: pipe which out fence will be requested for
4117  *
4118  * Marks this pipe for requesting an out fence at the next atomic commit
4119  * will contain the fd number of the out fence created by KMS.
4120  */
igt_pipe_request_out_fence(igt_pipe_t * pipe)4121 void igt_pipe_request_out_fence(igt_pipe_t *pipe)
4122 {
4123 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)&pipe->out_fence_fd);
4124 }
4125 
4126 /**
4127  * igt_wait_for_vblank_count:
4128  * @drm_fd: A drm file descriptor
4129  * @pipe: Pipe to wait_for_vblank on
4130  * @count: Number of vblanks to wait on
4131  *
4132  * Waits for a given number of vertical blank intervals
4133  */
igt_wait_for_vblank_count(int drm_fd,enum pipe pipe,int count)4134 void igt_wait_for_vblank_count(int drm_fd, enum pipe pipe, int count)
4135 {
4136 	drmVBlank wait_vbl;
4137 	uint32_t pipe_id_flag;
4138 
4139 	memset(&wait_vbl, 0, sizeof(wait_vbl));
4140 	pipe_id_flag = kmstest_get_vbl_flag(pipe);
4141 
4142 	wait_vbl.request.type = DRM_VBLANK_RELATIVE;
4143 	wait_vbl.request.type |= pipe_id_flag;
4144 	wait_vbl.request.sequence = count;
4145 
4146 	igt_assert(drmWaitVBlank(drm_fd, &wait_vbl) == 0);
4147 }
4148 
4149 /**
4150  * igt_wait_for_vblank:
4151  * @drm_fd: A drm file descriptor
4152  * @pipe: Pipe to wait_for_vblank on
4153  *
4154  * Waits for 1 vertical blank intervals
4155  */
igt_wait_for_vblank(int drm_fd,enum pipe pipe)4156 void igt_wait_for_vblank(int drm_fd, enum pipe pipe)
4157 {
4158 	igt_wait_for_vblank_count(drm_fd, pipe, 1);
4159 }
4160 
4161 /**
4162  * igt_enable_connectors:
4163  * @drm_fd: A drm file descriptor
4164  *
4165  * Force connectors to be enabled where this is known to work well. Use
4166  * #igt_reset_connectors to revert the changes.
4167  *
4168  * An exit handler is installed to ensure connectors are reset when the test
4169  * exits.
4170  */
igt_enable_connectors(int drm_fd)4171 void igt_enable_connectors(int drm_fd)
4172 {
4173 	drmModeRes *res;
4174 
4175 	res = drmModeGetResources(drm_fd);
4176 	if (!res)
4177 		return;
4178 
4179 	for (int i = 0; i < res->count_connectors; i++) {
4180 		drmModeConnector *c;
4181 
4182 		/* Do a probe. This may be the first action after booting */
4183 		c = drmModeGetConnector(drm_fd, res->connectors[i]);
4184 		if (!c) {
4185 			igt_warn("Could not read connector %u: %m\n", res->connectors[i]);
4186 			continue;
4187 		}
4188 
4189 		/* don't attempt to force connectors that are already connected
4190 		 */
4191 		if (c->connection == DRM_MODE_CONNECTED)
4192 			continue;
4193 
4194 		/* just enable VGA for now */
4195 		if (c->connector_type == DRM_MODE_CONNECTOR_VGA) {
4196 			if (!kmstest_force_connector(drm_fd, c, FORCE_CONNECTOR_ON))
4197 				igt_info("Unable to force state on %s-%d\n",
4198 					 kmstest_connector_type_str(c->connector_type),
4199 					 c->connector_type_id);
4200 		}
4201 
4202 		drmModeFreeConnector(c);
4203 	}
4204 }
4205 
4206 /**
4207  * igt_reset_connectors:
4208  *
4209  * Remove any forced state from the connectors.
4210  */
igt_reset_connectors(void)4211 void igt_reset_connectors(void)
4212 {
4213 	/* reset the connectors stored in forced_connectors, avoiding any
4214 	 * functions that are not safe to call in signal handlers */
4215 	for (int i = 0; forced_connectors[i]; i++)
4216 		igt_sysfs_set(forced_connectors_device[i],
4217 			      forced_connectors[i],
4218 			      "detect");
4219 }
4220 
4221 #if !defined(ANDROID)
4222 /**
4223  * igt_watch_hotplug:
4224  *
4225  * Begin monitoring udev for sysfs hotplug events.
4226  *
4227  * Returns: a udev monitor for detecting hotplugs on
4228  */
igt_watch_hotplug(void)4229 struct udev_monitor *igt_watch_hotplug(void)
4230 {
4231 	struct udev *udev;
4232 	struct udev_monitor *mon;
4233 	int ret, flags, fd;
4234 
4235 	udev = udev_new();
4236 	igt_assert(udev != NULL);
4237 
4238 	mon = udev_monitor_new_from_netlink(udev, "udev");
4239 	igt_assert(mon != NULL);
4240 
4241 	ret = udev_monitor_filter_add_match_subsystem_devtype(mon,
4242 							      "drm",
4243 							      "drm_minor");
4244 	igt_assert_eq(ret, 0);
4245 	ret = udev_monitor_filter_update(mon);
4246 	igt_assert_eq(ret, 0);
4247 	ret = udev_monitor_enable_receiving(mon);
4248 	igt_assert_eq(ret, 0);
4249 
4250 	/* Set the fd for udev as non blocking */
4251 	fd = udev_monitor_get_fd(mon);
4252 	flags = fcntl(fd, F_GETFL, 0);
4253 	igt_assert(flags);
4254 
4255 	flags |= O_NONBLOCK;
4256 	igt_assert_neq(fcntl(fd, F_SETFL, flags), -1);
4257 
4258 	return mon;
4259 }
4260 
event_detected(struct udev_monitor * mon,int timeout_secs,const char * property)4261 static bool event_detected(struct udev_monitor *mon, int timeout_secs,
4262 			   const char *property)
4263 {
4264 	struct udev_device *dev;
4265 	const char *hotplug_val;
4266 	struct pollfd fd = {
4267 		.fd = udev_monitor_get_fd(mon),
4268 		.events = POLLIN
4269 	};
4270 	bool hotplug_received = false;
4271 
4272 	/* Go through all of the events pending on the udev monitor. Once we
4273 	 * receive a hotplug, we continue going through the rest of the events
4274 	 * so that redundant hotplug events don't change the results of future
4275 	 * checks
4276 	 */
4277 	while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) {
4278 		dev = udev_monitor_receive_device(mon);
4279 
4280 		hotplug_val = udev_device_get_property_value(dev, property);
4281 		if (hotplug_val && atoi(hotplug_val) == 1)
4282 			hotplug_received = true;
4283 
4284 		udev_device_unref(dev);
4285 	}
4286 
4287 	return hotplug_received;
4288 }
4289 
4290 /**
4291  * igt_hotplug_detected:
4292  * @mon: A udev monitor initialized with #igt_watch_hotplug
4293  * @timeout_secs: How long to wait for a hotplug event to occur.
4294  *
4295  * Assert that a hotplug event was received since we last checked the monitor.
4296  *
4297  * Returns: true if a sysfs hotplug event was received, false if we timed out
4298  */
igt_hotplug_detected(struct udev_monitor * mon,int timeout_secs)4299 bool igt_hotplug_detected(struct udev_monitor *mon, int timeout_secs)
4300 {
4301 	return event_detected(mon, timeout_secs, "HOTPLUG");
4302 }
4303 
4304 /**
4305  * igt_lease_change_detected:
4306  * @mon: A udev monitor initialized with #igt_watch_hotplug
4307  * @timeout_secs: How long to wait for a lease change event to occur.
4308  *
4309  * Assert that a lease change event was received since we last checked the monitor.
4310  *
4311  * Returns: true if a sysfs lease change event was received, false if we timed out
4312  */
igt_lease_change_detected(struct udev_monitor * mon,int timeout_secs)4313 bool igt_lease_change_detected(struct udev_monitor *mon, int timeout_secs)
4314 {
4315 	return event_detected(mon, timeout_secs, "LEASE");
4316 }
4317 
4318 /**
4319  * igt_flush_hotplugs:
4320  * @mon: A udev monitor initialized with #igt_watch_hotplug
4321  *
4322  * Get rid of any pending hotplug events
4323  */
igt_flush_hotplugs(struct udev_monitor * mon)4324 void igt_flush_hotplugs(struct udev_monitor *mon)
4325 {
4326 	struct udev_device *dev;
4327 
4328 	while ((dev = udev_monitor_receive_device(mon)))
4329 		udev_device_unref(dev);
4330 }
4331 
4332 /**
4333  * igt_cleanup_hotplug:
4334  * @mon: A udev monitor initialized with #igt_watch_hotplug
4335  *
4336  * Cleanup the resources allocated by #igt_watch_hotplug
4337  */
igt_cleanup_hotplug(struct udev_monitor * mon)4338 void igt_cleanup_hotplug(struct udev_monitor *mon)
4339 {
4340 	struct udev *udev = udev_monitor_get_udev(mon);
4341 
4342 	udev_monitor_unref(mon);
4343 	mon = NULL;
4344 	udev_unref(udev);
4345 }
4346 #endif /*!defined(ANDROID)*/
4347 
4348 /**
4349  * kmstest_get_vbl_flag:
4350  * @pipe_id: Pipe to convert to flag representation.
4351  *
4352  * Convert a pipe id into the flag representation
4353  * expected in DRM while processing DRM_IOCTL_WAIT_VBLANK.
4354  */
kmstest_get_vbl_flag(uint32_t pipe_id)4355 uint32_t kmstest_get_vbl_flag(uint32_t pipe_id)
4356 {
4357 	if (pipe_id == 0)
4358 		return 0;
4359 	else if (pipe_id == 1)
4360 		return _DRM_VBLANK_SECONDARY;
4361 	else {
4362 		uint32_t pipe_flag = pipe_id << 1;
4363 		igt_assert(!(pipe_flag & ~DRM_VBLANK_HIGH_CRTC_MASK));
4364 		return pipe_flag;
4365 	}
4366 }
4367 
4368 static inline const uint32_t *
formats_ptr(const struct drm_format_modifier_blob * blob)4369 formats_ptr(const struct drm_format_modifier_blob *blob)
4370 {
4371 	return (const uint32_t *)((const char *)blob + blob->formats_offset);
4372 }
4373 
4374 static inline const struct drm_format_modifier *
modifiers_ptr(const struct drm_format_modifier_blob * blob)4375 modifiers_ptr(const struct drm_format_modifier_blob *blob)
4376 {
4377 	return (const struct drm_format_modifier *)((const char *)blob + blob->modifiers_offset);
4378 }
4379 
igt_count_plane_format_mod(const struct drm_format_modifier_blob * blob_data)4380 static int igt_count_plane_format_mod(const struct drm_format_modifier_blob *blob_data)
4381 {
4382 	const struct drm_format_modifier *modifiers;
4383 	int count = 0;
4384 
4385 	modifiers = modifiers_ptr(blob_data);
4386 
4387 	for (int i = 0; i < blob_data->count_modifiers; i++)
4388 		count += igt_hweight(modifiers[i].formats);
4389 
4390 	return count;
4391 }
4392 
igt_fill_plane_format_mod(igt_display_t * display,igt_plane_t * plane)4393 static void igt_fill_plane_format_mod(igt_display_t *display, igt_plane_t *plane)
4394 {
4395 	const struct drm_format_modifier_blob *blob_data;
4396 	drmModePropertyBlobPtr blob;
4397 	uint64_t blob_id;
4398 	int idx = 0;
4399 	int count;
4400 
4401 	if (!igt_plane_has_prop(plane, IGT_PLANE_IN_FORMATS)) {
4402 		drmModePlanePtr p = plane->drm_plane;
4403 
4404 		count = p->count_formats;
4405 
4406 		plane->format_mod_count = count;
4407 		plane->formats = calloc(count, sizeof(plane->formats[0]));
4408 		igt_assert(plane->formats);
4409 		plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4410 		igt_assert(plane->modifiers);
4411 
4412 		/*
4413 		 * We don't know which modifiers are
4414 		 * supported, so we'll assume linear only.
4415 		 */
4416 		for (int i = 0; i < count; i++) {
4417 			plane->formats[i] = p->formats[i];
4418 			plane->modifiers[i] = DRM_FORMAT_MOD_LINEAR;
4419 		}
4420 
4421 		return;
4422 	}
4423 
4424 	blob_id = igt_plane_get_prop(plane, IGT_PLANE_IN_FORMATS);
4425 
4426 	blob = drmModeGetPropertyBlob(display->drm_fd, blob_id);
4427 	if (!blob)
4428 		return;
4429 
4430 	blob_data = (const struct drm_format_modifier_blob *) blob->data;
4431 
4432 	count = igt_count_plane_format_mod(blob_data);
4433 	if (!count)
4434 		return;
4435 
4436 	plane->format_mod_count = count;
4437 	plane->formats = calloc(count, sizeof(plane->formats[0]));
4438 	igt_assert(plane->formats);
4439 	plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4440 	igt_assert(plane->modifiers);
4441 
4442 	for (int i = 0; i < blob_data->count_modifiers; i++) {
4443 		for (int j = 0; j < 64; j++) {
4444 			const struct drm_format_modifier *modifiers =
4445 				modifiers_ptr(blob_data);
4446 			const uint32_t *formats = formats_ptr(blob_data);
4447 
4448 			if (!(modifiers[i].formats & (1ULL << j)))
4449 				continue;
4450 
4451 			plane->formats[idx] = formats[modifiers[i].offset + j];
4452 			plane->modifiers[idx] = modifiers[i].modifier;
4453 			idx++;
4454 			igt_assert_lte(idx, plane->format_mod_count);
4455 		}
4456 	}
4457 
4458 	igt_assert_eq(idx, plane->format_mod_count);
4459 }
4460 
igt_plane_has_format_mod(igt_plane_t * plane,uint32_t format,uint64_t modifier)4461 bool igt_plane_has_format_mod(igt_plane_t *plane, uint32_t format,
4462 			      uint64_t modifier)
4463 {
4464 	int i;
4465 
4466 	for (i = 0; i < plane->format_mod_count; i++) {
4467 		if (plane->formats[i] == format &&
4468 		    plane->modifiers[i] == modifier)
4469 			return true;
4470 
4471 	}
4472 
4473 	return false;
4474 }
4475 
igt_count_display_format_mod(igt_display_t * display)4476 static int igt_count_display_format_mod(igt_display_t *display)
4477 {
4478 	enum pipe pipe;
4479 	int count = 0;
4480 
4481 	for_each_pipe(display, pipe) {
4482 		igt_plane_t *plane;
4483 
4484 		for_each_plane_on_pipe(display, pipe, plane) {
4485 			count += plane->format_mod_count;
4486 		}
4487 	}
4488 
4489 	return count;
4490 }
4491 
4492 static void
igt_add_display_format_mod(igt_display_t * display,uint32_t format,uint64_t modifier)4493 igt_add_display_format_mod(igt_display_t *display, uint32_t format,
4494 			   uint64_t modifier)
4495 {
4496 	int i;
4497 
4498 	for (i = 0; i < display->format_mod_count; i++) {
4499 		if (display->formats[i] == format &&
4500 		    display->modifiers[i] == modifier)
4501 			return;
4502 
4503 	}
4504 
4505 	display->formats[i] = format;
4506 	display->modifiers[i] = modifier;
4507 	display->format_mod_count++;
4508 }
4509 
igt_fill_display_format_mod(igt_display_t * display)4510 static void igt_fill_display_format_mod(igt_display_t *display)
4511 {
4512 	int count = igt_count_display_format_mod(display);
4513 	enum pipe pipe;
4514 
4515 	if (!count)
4516 		return;
4517 
4518 	display->formats = calloc(count, sizeof(display->formats[0]));
4519 	igt_assert(display->formats);
4520 	display->modifiers = calloc(count, sizeof(display->modifiers[0]));
4521 	igt_assert(display->modifiers);
4522 
4523 	for_each_pipe(display, pipe) {
4524 		igt_plane_t *plane;
4525 
4526 		for_each_plane_on_pipe(display, pipe, plane) {
4527 			for (int i = 0; i < plane->format_mod_count; i++) {
4528 				igt_add_display_format_mod(display,
4529 							   plane->formats[i],
4530 							   plane->modifiers[i]);
4531 				igt_assert_lte(display->format_mod_count, count);
4532 			}
4533 		}
4534 	}
4535 }
4536 
igt_display_has_format_mod(igt_display_t * display,uint32_t format,uint64_t modifier)4537 bool igt_display_has_format_mod(igt_display_t *display, uint32_t format,
4538 				uint64_t modifier)
4539 {
4540 	int i;
4541 
4542 	for (i = 0; i < display->format_mod_count; i++) {
4543 		if (display->formats[i] == format &&
4544 		    display->modifiers[i] == modifier)
4545 			return true;
4546 
4547 	}
4548 
4549 	return false;
4550 }
4551