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