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