blob: 2d77510668549f3a72a46e5eddc30fc09ae29616 [file] [log] [blame]
Oscar Mateo37f26d12013-11-12 11:50:38 +00001/*
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 *
Daniel Vetter57d7db82014-03-26 09:06:11 +010023 * Authors:
24 * Daniel Vetter <daniel.vetter@ffwll.ch>
25 * Damien Lespiau <damien.lespiau@intel.com>
Oscar Mateo37f26d12013-11-12 11:50:38 +000026 */
27
Alan Coopersmithcf93bc82014-12-23 19:07:09 -080028#include "config.h"
Daniel Vetter254f19b2014-03-22 21:29:01 +010029#include <unistd.h>
Oscar Mateo37f26d12013-11-12 11:50:38 +000030#include <stdio.h>
Damien Lespiau3670d6d2014-01-27 16:25:43 +000031#include <stdarg.h>
Oscar Mateo37f26d12013-11-12 11:50:38 +000032#include <fcntl.h>
33#include <sys/stat.h>
34#include <string.h>
Daniel Vetter254f19b2014-03-22 21:29:01 +010035#include <stdlib.h>
Alan Coopersmithcf93bc82014-12-23 19:07:09 -080036#ifdef HAVE_LINUX_KD_H
Oscar Mateo37f26d12013-11-12 11:50:38 +000037#include <linux/kd.h>
Alan Coopersmithcf93bc82014-12-23 19:07:09 -080038#elif HAVE_SYS_KD_H
39#include <sys/kd.h>
40#endif
Lyude6adb7b32016-11-17 10:06:09 -050041#ifdef HAVE_UDEV
42#include <libudev.h>
43#include <poll.h>
44#endif
Daniel Vetter254f19b2014-03-22 21:29:01 +010045#include <errno.h>
Thomas Wood273a06d2014-10-08 14:11:30 +010046#include <time.h>
Daniel Vetter254f19b2014-03-22 21:29:01 +010047
Daniel Vetter57d7db82014-03-26 09:06:11 +010048#include <i915_drm.h>
49
Oscar Mateo37f26d12013-11-12 11:50:38 +000050#include "drmtest.h"
51#include "igt_kms.h"
Daniel Vetterf5daeec2014-03-23 13:35:09 +010052#include "igt_aux.h"
Thomas Woodd3c83b22014-09-04 16:56:17 +010053#include "intel_chipset.h"
Thomas Woodc049c392014-11-03 13:48:51 +000054#include "igt_debugfs.h"
Chris Wilson0e11bef2016-05-26 15:06:30 +010055#include "igt_sysfs.h"
Robert Foss187ccf02017-01-31 11:43:35 -050056#include "sw_sync.h"
Oscar Mateo37f26d12013-11-12 11:50:38 +000057
Maarten Lankhorst9ed1af62016-07-27 14:12:40 +020058/**
59 * SECTION:igt_kms
60 * @short_description: Kernel modesetting support library
61 * @title: KMS
62 * @include: igt.h
63 *
64 * This library provides support to enumerate and set modeset configurations.
65 *
66 * There are two parts in this library: First the low level helper function
67 * which directly build on top of raw ioctls or the interfaces provided by
68 * libdrm. Those functions all have a kmstest_ prefix.
69 *
70 * The second part is a high-level library to manage modeset configurations
71 * which abstracts away some of the low-level details like the difference
72 * between legacy and universal plane support for setting cursors or in the
73 * future the difference between legacy and atomic commit. These high-level
74 * functions have all igt_ prefixes. This part is still very much work in
75 * progress and so also lacks a bit documentation for the individual functions.
76 *
77 * Note that this library's header pulls in the [i-g-t framebuffer](intel-gpu-tools-i-g-t-framebuffer.html)
78 * library as a dependency.
79 */
80
Thomas Woodf675f672014-09-04 11:35:01 +010081/* list of connectors that need resetting on exit */
82#define MAX_CONNECTORS 32
83static char *forced_connectors[MAX_CONNECTORS + 1];
Chris Wilson0e11bef2016-05-26 15:06:30 +010084static int forced_connectors_device[MAX_CONNECTORS + 1];
Matt Roperc8b8f8a2014-07-07 09:08:29 -070085
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +030086static void update_edid_csum(unsigned char *edid, int cea_pos)
Ville Syrjäläb0f4df32015-12-03 19:01:21 +020087{
88 int i, sum = 0;
89 struct tm *tm;
90 time_t t;
91
92 /* year of manufacture */
93 t = time(NULL);
94 tm = localtime(&t);
95 edid[17] = tm->tm_year - 90;
96
97 /* calculate checksum */
98 for (i = 0; i < 127; i++) {
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +030099 sum = sum + edid[cea_pos + i];
Ville Syrjäläb0f4df32015-12-03 19:01:21 +0200100 }
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +0300101 edid[cea_pos + 127] = 256 - sum;
Ville Syrjäläb0f4df32015-12-03 19:01:21 +0200102}
Matt Roperc8b8f8a2014-07-07 09:08:29 -0700103
Thomas Wood273a06d2014-10-08 14:11:30 +0100104#define VFREQ 60
105#define CLOCK 148500
106#define HACTIVE 1920
107#define HBLANK 280
108#define VACTIVE 1080
109#define VBLANK 45
110#define HOFFSET 88
111#define HPULSE 44
112#define VOFFSET 4
113#define VPULSE 5
114
115#define HSIZE 52
116#define VSIZE 30
117
Ville Syrjäläb0f4df32015-12-03 19:01:21 +0200118#define EDID_NAME base_edid
119#include "igt_edid_template.h"
Thomas Wood273a06d2014-10-08 14:11:30 +0100120
121/**
122 * igt_kms_get_base_edid:
123 *
124 * Get the base edid block, which includes the following modes:
125 *
126 * - 1920x1080 60Hz
127 * - 1280x720 60Hz
128 * - 1024x768 60Hz
129 * - 800x600 60Hz
130 * - 640x480 60Hz
131 *
132 * This can be extended with further features using functions such as
133 * #kmstest_edid_add_3d.
134 *
135 * Returns: a basic edid block
136 */
137const unsigned char* igt_kms_get_base_edid(void)
138{
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +0300139 update_edid_csum(base_edid, 0);
Thomas Wood273a06d2014-10-08 14:11:30 +0100140
141 return base_edid;
142}
143
Ville Syrjälä870548b2015-12-04 15:49:30 +0200144#define VFREQ 60
145#define CLOCK 101000
146#define HACTIVE 1400
147#define HBLANK 160
148#define VACTIVE 1050
149#define VBLANK 30
150#define HOFFSET 48
151#define HPULSE 32
152#define VOFFSET 3
153#define VPULSE 4
154
155#define HSIZE 52
156#define VSIZE 30
157
158#define EDID_NAME alt_edid
159#include "igt_edid_template.h"
160
Gustavo Padovane707ace2016-10-26 12:14:43 +0000161const char *igt_plane_prop_names[IGT_NUM_PLANE_PROPS] = {
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530162 "SRC_X",
163 "SRC_Y",
164 "SRC_W",
165 "SRC_H",
166 "CRTC_X",
167 "CRTC_Y",
168 "CRTC_W",
169 "CRTC_H",
170 "FB_ID",
171 "CRTC_ID",
Robert Foss221848d2016-06-20 10:24:08 -0400172 "IN_FENCE_FD",
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530173 "type",
174 "rotation"
175};
176
Gustavo Padovane707ace2016-10-26 12:14:43 +0000177const char *igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = {
Lionel Landwerlin17166252016-03-18 17:33:01 +0000178 "background_color",
Lionel Landwerlin17166252016-03-18 17:33:01 +0000179 "CTM",
Robert Fossbe3bf602016-06-29 07:22:52 -0400180 "DEGAMMA_LUT",
Lionel Landwerlin17166252016-03-18 17:33:01 +0000181 "GAMMA_LUT",
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +0200182 "MODE_ID",
Gustavo Padovan513846b2016-06-20 10:24:08 -0400183 "ACTIVE",
184 "OUT_FENCE_PTR"
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530185};
186
Gustavo Padovane707ace2016-10-26 12:14:43 +0000187const char *igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530188 "scaling mode",
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +0200189 "CRTC_ID"
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530190};
191
192/*
193 * Retrieve all the properies specified in props_name and store them into
194 * plane->atomic_props_plane.
195 */
196static void
197igt_atomic_fill_plane_props(igt_display_t *display, igt_plane_t *plane,
198 int num_props, const char **prop_names)
199{
200 drmModeObjectPropertiesPtr props;
201 int i, j, fd;
202
203 fd = display->drm_fd;
204
205 props = drmModeObjectGetProperties(fd, plane->drm_plane->plane_id, DRM_MODE_OBJECT_PLANE);
206 igt_assert(props);
207
208 for (i = 0; i < props->count_props; i++) {
209 drmModePropertyPtr prop =
210 drmModeGetProperty(fd, props->props[i]);
211
212 for (j = 0; j < num_props; j++) {
213 if (strcmp(prop->name, prop_names[j]) != 0)
214 continue;
215
216 plane->atomic_props_plane[j] = props->props[i];
217 break;
218 }
219
220 drmModeFreeProperty(prop);
221 }
222
223 drmModeFreeObjectProperties(props);
224}
225
226/*
227 * Retrieve all the properies specified in props_name and store them into
Maarten Lankhorst0404de42016-06-29 15:56:28 +0200228 * config->atomic_props_crtc and config->atomic_props_connector.
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530229 */
230static void
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200231igt_atomic_fill_connector_props(igt_display_t *display, igt_output_t *output,
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530232 int num_connector_props, const char **conn_prop_names)
233{
234 drmModeObjectPropertiesPtr props;
235 int i, j, fd;
236
237 fd = display->drm_fd;
238
Maarten Lankhorst0404de42016-06-29 15:56:28 +0200239 props = drmModeObjectGetProperties(fd, output->config.connector->connector_id, DRM_MODE_OBJECT_CONNECTOR);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530240 igt_assert(props);
241
242 for (i = 0; i < props->count_props; i++) {
243 drmModePropertyPtr prop =
244 drmModeGetProperty(fd, props->props[i]);
245
246 for (j = 0; j < num_connector_props; j++) {
247 if (strcmp(prop->name, conn_prop_names[j]) != 0)
248 continue;
249
250 output->config.atomic_props_connector[j] = props->props[i];
251 break;
252 }
253
254 drmModeFreeProperty(prop);
255 }
256
257 drmModeFreeObjectProperties(props);
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200258}
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530259
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200260static void
261igt_atomic_fill_pipe_props(igt_display_t *display, igt_pipe_t *pipe,
262 int num_crtc_props, const char **crtc_prop_names)
263{
264 drmModeObjectPropertiesPtr props;
265 int i, j, fd;
266
267 fd = display->drm_fd;
268
269 props = drmModeObjectGetProperties(fd, pipe->crtc_id, DRM_MODE_OBJECT_CRTC);
270 igt_assert(props);
271
272 for (i = 0; i < props->count_props; i++) {
273 drmModePropertyPtr prop =
274 drmModeGetProperty(fd, props->props[i]);
275
276 for (j = 0; j < num_crtc_props; j++) {
277 if (strcmp(prop->name, crtc_prop_names[j]) != 0)
278 continue;
279
280 pipe->atomic_props_crtc[j] = props->props[i];
281 break;
282 }
283
284 drmModeFreeProperty(prop);
285 }
286
287 drmModeFreeObjectProperties(props);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530288}
289
Gustavo Padovanedf4f1f2016-10-26 11:56:47 +0000290/**
291 * igt_kms_get_alt_edid:
292 *
293 * Get an alternate edid block, which includes the following modes:
294 *
295 * - 1400x1050 60Hz
296 * - 1920x1080 60Hz
297 * - 1280x720 60Hz
298 * - 1024x768 60Hz
299 * - 800x600 60Hz
300 * - 640x480 60Hz
301 *
302 * This can be extended with further features using functions such as
303 * #kmstest_edid_add_3d.
304 *
305 * Returns: an alternate edid block
306 */
Ville Syrjälä870548b2015-12-04 15:49:30 +0200307const unsigned char* igt_kms_get_alt_edid(void)
308{
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +0300309 update_edid_csum(alt_edid, 0);
Ville Syrjälä870548b2015-12-04 15:49:30 +0200310
311 return alt_edid;
312}
Thomas Wood273a06d2014-10-08 14:11:30 +0100313
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +0100314/**
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200315 * kmstest_pipe_name:
316 * @pipe: display pipe
317 *
Robert Foss3b453f72017-01-10 13:33:41 -0500318 * Returns: String representing @pipe, e.g. "A".
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200319 */
320const char *kmstest_pipe_name(enum pipe pipe)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000321{
322 const char *str[] = { "A", "B", "C" };
323
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +0200324 if (pipe == PIPE_NONE)
325 return "None";
326
Oscar Mateo37f26d12013-11-12 11:50:38 +0000327 if (pipe > 2)
328 return "invalid";
329
330 return str[pipe];
331}
332
Daniel Vetter27a19de2014-08-12 11:04:49 +0200333/**
Mika Kahola12e34d82016-11-23 11:19:37 +0200334 * kmstest_pipe_to_index:
335 *@pipe: display pipe in string format
336 *
337 * Returns: index to corresponding pipe
338 */
339int kmstest_pipe_to_index(char pipe)
340{
341 if (pipe == 'A')
342 return 0;
343 else if (pipe == 'B')
344 return 1;
345 else if (pipe == 'C')
346 return 2;
347 else
348 return -EINVAL;
349}
350
351/**
Robert Foss36656232017-01-18 12:28:45 -0500352 * kmstest_plane_type_name:
353 * @plane: display plane
354 *
355 * Returns: String representing @plane, e.g. "overlay".
356 */
357const char *kmstest_plane_type_name(int plane_type)
358{
359 static const char *names[] = {
360 [DRM_PLANE_TYPE_OVERLAY] = "overlay",
361 [DRM_PLANE_TYPE_PRIMARY] = "primary",
362 [DRM_PLANE_TYPE_CURSOR] = "cursor",
363 };
364
365 igt_assert(plane_type < ARRAY_SIZE(names) && names[plane_type]);
366
367 return names[plane_type];
368}
369
Oscar Mateo37f26d12013-11-12 11:50:38 +0000370static const char *mode_stereo_name(const drmModeModeInfo *mode)
371{
372 switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
373 case DRM_MODE_FLAG_3D_FRAME_PACKING:
374 return "FP";
375 case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
376 return "FA";
377 case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
378 return "LA";
379 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
380 return "SBSF";
381 case DRM_MODE_FLAG_3D_L_DEPTH:
382 return "LD";
383 case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
384 return "LDGFX";
385 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
386 return "TB";
387 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
388 return "SBSH";
389 default:
390 return NULL;
391 }
392}
393
Daniel Vetter27a19de2014-08-12 11:04:49 +0200394/**
395 * kmstest_dump_mode:
396 * @mode: libdrm mode structure
397 *
Ville Syrjälä9afd5452016-08-05 13:36:42 +0300398 * Prints @mode to stdout in a human-readable form.
Daniel Vetter27a19de2014-08-12 11:04:49 +0200399 */
Oscar Mateo37f26d12013-11-12 11:50:38 +0000400void kmstest_dump_mode(drmModeModeInfo *mode)
401{
402 const char *stereo = mode_stereo_name(mode);
403
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200404 igt_info(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s\n",
405 mode->name, mode->vrefresh,
406 mode->hdisplay, mode->hsync_start,
407 mode->hsync_end, mode->htotal,
408 mode->vdisplay, mode->vsync_start,
409 mode->vsync_end, mode->vtotal,
410 mode->flags, mode->type, mode->clock,
411 stereo ? " (3D:" : "",
412 stereo ? stereo : "", stereo ? ")" : "");
Oscar Mateo37f26d12013-11-12 11:50:38 +0000413}
414
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200415/**
416 * kmstest_get_pipe_from_crtc_id:
417 * @fd: DRM fd
418 * @crtc_id: DRM CRTC id
419 *
Micah Fedkebe354f42016-03-09 16:57:37 +0100420 * Returns: The crtc index for the given DRM CRTC ID @crtc_id. The crtc index
421 * is the equivalent of the pipe id. This value maps directly to an enum pipe
422 * value used in other helper functions. Returns 0 if the index could not be
423 * determined.
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200424 */
Micah Fedkebe354f42016-03-09 16:57:37 +0100425
Oscar Mateo37f26d12013-11-12 11:50:38 +0000426int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
427{
Micah Fedkebe354f42016-03-09 16:57:37 +0100428 drmModeRes *res;
429 drmModeCrtc *crtc;
430 int i, cur_id;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000431
Micah Fedkebe354f42016-03-09 16:57:37 +0100432 res = drmModeGetResources(fd);
433 igt_assert(res);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000434
Micah Fedkebe354f42016-03-09 16:57:37 +0100435 for (i = 0; i < res->count_crtcs; i++) {
436 crtc = drmModeGetCrtc(fd, res->crtcs[i]);
437 igt_assert(crtc);
438 cur_id = crtc->crtc_id;
439 drmModeFreeCrtc(crtc);
440 if (cur_id == crtc_id)
441 break;
442 }
443
Micah Fedkebe354f42016-03-09 16:57:37 +0100444 igt_assert(i < res->count_crtcs);
445
Tvrtko Ursulin1aebeeb2016-04-27 15:58:24 +0100446 drmModeFreeResources(res);
447
Micah Fedkebe354f42016-03-09 16:57:37 +0100448 return i;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000449}
450
Paulo Zanonid8bf28f2016-02-26 11:27:20 -0300451/**
452 * kmstest_find_crtc_for_connector:
453 * @fd: DRM fd
454 * @res: libdrm resources pointer
455 * @connector: libdrm connector pointer
456 * @crtc_blacklist_idx_mask: a mask of CRTC indexes that we can't return
457 *
458 * Returns: the CRTC ID for a CRTC that fits the connector, otherwise it asserts
459 * false and never returns. The blacklist mask can be used in case you have
460 * CRTCs that are already in use by other connectors.
461 */
462uint32_t kmstest_find_crtc_for_connector(int fd, drmModeRes *res,
463 drmModeConnector *connector,
464 uint32_t crtc_blacklist_idx_mask)
465{
466 drmModeEncoder *e;
467 uint32_t possible_crtcs;
468 int i, j;
469
470 for (i = 0; i < connector->count_encoders; i++) {
471 e = drmModeGetEncoder(fd, connector->encoders[i]);
472 possible_crtcs = e->possible_crtcs & ~crtc_blacklist_idx_mask;
473 drmModeFreeEncoder(e);
474
475 for (j = 0; possible_crtcs >> j; j++)
476 if (possible_crtcs & (1 << j))
477 return res->crtcs[j];
478 }
479
480 igt_assert(false);
481}
482
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100483/**
484 * kmstest_dumb_create:
485 * @fd: open drm file descriptor
486 * @width: width of the buffer in pixels
487 * @height: height of the buffer in pixels
488 * @bpp: bytes per pixel of the buffer
Maarten Lankhorst2d672a12016-07-27 15:33:12 +0200489 * @stride: Pointer which receives the dumb bo's stride, can be NULL.
490 * @size: Pointer which receives the dumb bo's size, can be NULL.
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100491 *
492 * This wraps the CREATE_DUMB ioctl, which allocates a new dumb buffer object
493 * for the specified dimensions.
494 *
495 * Returns: The file-private handle of the created buffer object
496 */
497uint32_t kmstest_dumb_create(int fd, int width, int height, int bpp,
498 unsigned *stride, unsigned *size)
499{
500 struct drm_mode_create_dumb create;
501
502 memset(&create, 0, sizeof(create));
503 create.width = width;
504 create.height = height;
505 create.bpp = bpp;
506
507 create.handle = 0;
508 do_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
509 igt_assert(create.handle);
510 igt_assert(create.size >= width * height * bpp / 8);
511
512 if (stride)
513 *stride = create.pitch;
514
515 if (size)
516 *size = create.size;
517
518 return create.handle;
519}
520
Tomeu Vizosofb66a5d2016-03-07 16:37:36 +0100521void *kmstest_dumb_map_buffer(int fd, uint32_t handle, uint64_t size,
522 unsigned prot)
523{
524 struct drm_mode_map_dumb arg = {};
525 void *ptr;
526
527 arg.handle = handle;
528
529 do_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
530
531 ptr = mmap(NULL, size, prot, MAP_SHARED, fd, arg.offset);
532 igt_assert(ptr != MAP_FAILED);
533
534 return ptr;
535}
536
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800537/*
538 * Returns: the previous mode, or KD_GRAPHICS if no /dev/tty0 was
539 * found and nothing was done.
540 */
Oscar Mateo37f26d12013-11-12 11:50:38 +0000541static signed long set_vt_mode(unsigned long mode)
542{
543 int fd;
544 unsigned long prev_mode;
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800545 static const char TTY0[] = "/dev/tty0";
Oscar Mateo37f26d12013-11-12 11:50:38 +0000546
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800547 if (access(TTY0, F_OK)) {
548 /* errno message should be "No such file". Do not
549 hardcode but ask strerror() in the very unlikely
550 case something else happened. */
551 igt_debug("VT: %s: %s, cannot change its mode\n",
552 TTY0, strerror(errno));
553 return KD_GRAPHICS;
554 }
555
556 fd = open(TTY0, O_RDONLY);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000557 if (fd < 0)
558 return -errno;
559
560 prev_mode = 0;
561 if (drmIoctl(fd, KDGETMODE, &prev_mode))
562 goto err;
563 if (drmIoctl(fd, KDSETMODE, (void *)mode))
564 goto err;
565
566 close(fd);
567
568 return prev_mode;
569err:
570 close(fd);
571
572 return -errno;
573}
574
575static unsigned long orig_vt_mode = -1UL;
576
Thomas Woodfcb324c2014-08-14 13:59:02 +0100577/**
578 * kmstest_restore_vt_mode:
579 *
580 * Restore the VT mode in use before #kmstest_set_vt_graphics_mode was called.
581 */
582void kmstest_restore_vt_mode(void)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000583{
Thomas Woodfcb324c2014-08-14 13:59:02 +0100584 long ret;
585
586 if (orig_vt_mode != -1UL) {
587 ret = set_vt_mode(orig_vt_mode);
Thomas Woodfcb324c2014-08-14 13:59:02 +0100588
589 igt_assert(ret >= 0);
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800590 igt_debug("VT: original mode 0x%lx restored\n", orig_vt_mode);
591 orig_vt_mode = -1UL;
Thomas Woodfcb324c2014-08-14 13:59:02 +0100592 }
Oscar Mateo37f26d12013-11-12 11:50:38 +0000593}
594
Daniel Vetter33f08842014-08-12 11:23:09 +0200595/**
596 * kmstest_set_vt_graphics_mode:
597 *
Thomas Woodfcb324c2014-08-14 13:59:02 +0100598 * Sets the controlling VT (if available) into graphics/raw mode and installs
599 * an igt exit handler to set the VT back to text mode on exit. Use
600 * #kmstest_restore_vt_mode to restore the previous VT mode manually.
Daniel Vetter33f08842014-08-12 11:23:09 +0200601 *
602 * All kms tests must call this function to make sure that the fbcon doesn't
603 * interfere by e.g. blanking the screen.
Oscar Mateo37f26d12013-11-12 11:50:38 +0000604 */
Daniel Vetter33f08842014-08-12 11:23:09 +0200605void kmstest_set_vt_graphics_mode(void)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000606{
Thomas Wood0269d1d2014-02-06 16:31:54 +0000607 long ret;
608
Thomas Woodfcb324c2014-08-14 13:59:02 +0100609 igt_install_exit_handler((igt_exit_handler_t) kmstest_restore_vt_mode);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000610
Thomas Wood0269d1d2014-02-06 16:31:54 +0000611 ret = set_vt_mode(KD_GRAPHICS);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000612
Thomas Wood0269d1d2014-02-06 16:31:54 +0000613 igt_assert(ret >= 0);
614 orig_vt_mode = ret;
Thomas Woodfcb324c2014-08-14 13:59:02 +0100615
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800616 igt_debug("VT: graphics mode set (mode was 0x%lx)\n", ret);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000617}
618
Thomas Woodc76f3532014-12-03 14:38:45 +0000619
620static void reset_connectors_at_exit(int sig)
621{
622 igt_reset_connectors();
623}
624
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200625/**
626 * kmstest_force_connector:
627 * @fd: drm file descriptor
628 * @connector: connector
629 * @state: state to force on @connector
630 *
631 * Force the specified state on the specified connector.
632 *
633 * Returns: true on success
634 */
635bool kmstest_force_connector(int drm_fd, drmModeConnector *connector,
636 enum kmstest_force_connector_state state)
637{
Thomas Woodf675f672014-09-04 11:35:01 +0100638 char *path, **tmp;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200639 const char *value;
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100640 drmModeConnector *temp;
Thomas Woodd3c83b22014-09-04 16:56:17 +0100641 uint32_t devid;
Chris Wilson0e11bef2016-05-26 15:06:30 +0100642 int len, dir, idx;
Thomas Woodd3c83b22014-09-04 16:56:17 +0100643
Lyude81677442016-11-21 17:32:39 -0500644 if (is_i915_device(drm_fd)) {
645 devid = intel_get_drm_devid(drm_fd);
Thomas Woodd3c83b22014-09-04 16:56:17 +0100646
Lyude81677442016-11-21 17:32:39 -0500647 /*
648 * forcing hdmi or dp connectors on HSW and BDW doesn't
649 * currently work, so fail early to allow the test to skip if
650 * required
651 */
652 if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
653 connector->connector_type == DRM_MODE_CONNECTOR_HDMIB ||
654 connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
655 && (IS_HASWELL(devid) || IS_BROADWELL(devid)))
656 return false;
657 }
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200658
659 switch (state) {
660 case FORCE_CONNECTOR_ON:
661 value = "on";
662 break;
663 case FORCE_CONNECTOR_DIGITAL:
Chris Wilson0e11bef2016-05-26 15:06:30 +0100664 value = "on-digital";
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200665 break;
666 case FORCE_CONNECTOR_OFF:
667 value = "off";
668 break;
669
670 default:
671 case FORCE_CONNECTOR_UNSPECIFIED:
Chris Wilson0e11bef2016-05-26 15:06:30 +0100672 value = "detect";
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200673 break;
674 }
675
Chris Wilson0e11bef2016-05-26 15:06:30 +0100676 dir = igt_sysfs_open(drm_fd, &idx);
677 if (dir < 0)
678 return false;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200679
Chris Wilson0e11bef2016-05-26 15:06:30 +0100680 if (asprintf(&path, "card%d-%s-%d/status",
681 idx,
682 kmstest_connector_type_str(connector->connector_type),
683 connector->connector_type_id) < 0) {
684 close(dir);
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200685 return false;
686 }
687
Marius Vlad32940a02016-06-03 20:51:10 +0300688 if (!igt_sysfs_set(dir, path, value)) {
Chris Wilson0e11bef2016-05-26 15:06:30 +0100689 close(dir);
690 return false;
691 }
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200692
Thomas Woodf675f672014-09-04 11:35:01 +0100693 for (len = 0, tmp = forced_connectors; *tmp; tmp++) {
694 /* check the connector is not already present */
695 if (strcmp(*tmp, path) == 0) {
696 len = -1;
697 break;
698 }
699 len++;
700 }
701
Chris Wilson0e11bef2016-05-26 15:06:30 +0100702 if (len != -1 && len < MAX_CONNECTORS) {
Thomas Woodf675f672014-09-04 11:35:01 +0100703 forced_connectors[len] = path;
Chris Wilson0e11bef2016-05-26 15:06:30 +0100704 forced_connectors_device[len] = dir;
705 }
Thomas Woodf675f672014-09-04 11:35:01 +0100706
707 if (len >= MAX_CONNECTORS)
708 igt_warn("Connector limit reached, %s will not be reset\n",
709 path);
710
711 igt_debug("Connector %s is now forced %s\n", path, value);
712 igt_debug("Current forced connectors:\n");
713 tmp = forced_connectors;
714 while (*tmp) {
715 igt_debug("\t%s\n", *tmp);
716 tmp++;
717 }
718
Thomas Woodc76f3532014-12-03 14:38:45 +0000719 igt_install_exit_handler(reset_connectors_at_exit);
Thomas Woodf675f672014-09-04 11:35:01 +0100720
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100721 /* To allow callers to always use GetConnectorCurrent we need to force a
722 * redetection here. */
723 temp = drmModeGetConnector(drm_fd, connector->connector_id);
724 drmModeFreeConnector(temp);
725
Chris Wilson0e11bef2016-05-26 15:06:30 +0100726 return true;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200727}
728
729/**
730 * kmstest_force_edid:
731 * @drm_fd: drm file descriptor
732 * @connector: connector to set @edid on
733 * @edid: An EDID data block
734 * @length: length of the EDID data. #EDID_LENGTH defines the standard EDID
735 * length
736 *
Thomas Wood8d82e5b2014-10-08 16:16:39 +0100737 * Set the EDID data on @connector to @edid. See also #igt_kms_get_base_edid.
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200738 *
739 * If @length is zero, the forced EDID will be removed.
740 */
741void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
742 const unsigned char *edid, size_t length)
743{
744 char *path;
745 int debugfs_fd, ret;
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100746 drmModeConnector *temp;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200747
Thomas Wood47f6b132015-03-25 16:42:57 +0000748 igt_assert_neq(asprintf(&path, "%s-%d/edid_override", kmstest_connector_type_str(connector->connector_type), connector->connector_type_id),
749 -1);
Chris Wilson83884e92017-03-21 17:16:03 +0000750 debugfs_fd = igt_debugfs_open(drm_fd, path, O_WRONLY | O_TRUNC);
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200751 free(path);
752
753 igt_assert(debugfs_fd != -1);
754
755 if (length == 0)
756 ret = write(debugfs_fd, "reset", 5);
757 else
758 ret = write(debugfs_fd, edid, length);
759 close(debugfs_fd);
760
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100761 /* To allow callers to always use GetConnectorCurrent we need to force a
762 * redetection here. */
763 temp = drmModeGetConnector(drm_fd, connector->connector_id);
764 drmModeFreeConnector(temp);
765
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200766 igt_assert(ret != -1);
767}
768
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200769/**
770 * kmstest_get_connector_default_mode:
771 * @drm_fd: DRM fd
772 * @connector: libdrm connector
773 * @mode: libdrm mode
774 *
775 * Retrieves the default mode for @connector and stores it in @mode.
776 *
777 * Returns: true on success, false on failure
778 */
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200779bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
780 drmModeModeInfo *mode)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000781{
Oscar Mateo37f26d12013-11-12 11:50:38 +0000782 int i;
783
Oscar Mateo37f26d12013-11-12 11:50:38 +0000784 if (!connector->count_modes) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200785 igt_warn("no modes for connector %d\n",
786 connector->connector_id);
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200787 return false;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000788 }
789
790 for (i = 0; i < connector->count_modes; i++) {
791 if (i == 0 ||
792 connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
793 *mode = connector->modes[i];
794 if (mode->type & DRM_MODE_TYPE_PREFERRED)
795 break;
796 }
797 }
798
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200799 return true;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000800}
801
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +0200802static void
803_kmstest_connector_config_crtc_mask(int drm_fd,
804 drmModeConnector *connector,
805 struct kmstest_connector_config *config)
806{
807 int i;
808
809 config->valid_crtc_idx_mask = 0;
810
811 /* Now get a compatible encoder */
812 for (i = 0; i < connector->count_encoders; i++) {
813 drmModeEncoder *encoder = drmModeGetEncoder(drm_fd,
814 connector->encoders[i]);
815
816 if (!encoder) {
817 igt_warn("could not get encoder %d: %s\n",
818 connector->encoders[i],
819 strerror(errno));
820
821 continue;
822 }
823
824 config->valid_crtc_idx_mask |= encoder->possible_crtcs;
825 drmModeFreeEncoder(encoder);
826 }
827}
828
829static drmModeEncoder *
830_kmstest_connector_config_find_encoder(int drm_fd, drmModeConnector *connector, enum pipe pipe)
831{
832 int i;
833
834 for (i = 0; i < connector->count_encoders; i++) {
835 drmModeEncoder *encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
836
837 if (!encoder) {
838 igt_warn("could not get encoder %d: %s\n",
839 connector->encoders[i],
840 strerror(errno));
841
842 continue;
843 }
844
845 if (encoder->possible_crtcs & (1 << pipe))
846 return encoder;
847
848 drmModeFreeEncoder(encoder);
849 }
850
851 igt_assert(false);
852 return NULL;
853}
854
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200855/**
Jesse Barnese28acef2016-01-14 14:03:53 -0800856 * _kmstest_connector_config:
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200857 * @drm_fd: DRM fd
858 * @connector_id: DRM connector id
859 * @crtc_idx_mask: mask of allowed DRM CRTC indices
860 * @config: structure filled with the possible configuration
Jesse Barnese28acef2016-01-14 14:03:53 -0800861 * @probe: whether to fully re-probe mode list or not
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200862 *
863 * This tries to find a suitable configuration for the given connector and CRTC
864 * constraint and fills it into @config.
865 */
Jesse Barnese28acef2016-01-14 14:03:53 -0800866static bool _kmstest_connector_config(int drm_fd, uint32_t connector_id,
867 unsigned long crtc_idx_mask,
868 struct kmstest_connector_config *config,
869 bool probe)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000870{
871 drmModeRes *resources;
872 drmModeConnector *connector;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000873
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +0200874 config->pipe = PIPE_NONE;
875
Oscar Mateo37f26d12013-11-12 11:50:38 +0000876 resources = drmModeGetResources(drm_fd);
877 if (!resources) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200878 igt_warn("drmModeGetResources failed");
Oscar Mateo37f26d12013-11-12 11:50:38 +0000879 goto err1;
880 }
881
882 /* First, find the connector & mode */
Jesse Barnese28acef2016-01-14 14:03:53 -0800883 if (probe)
884 connector = drmModeGetConnector(drm_fd, connector_id);
885 else
886 connector = drmModeGetConnectorCurrent(drm_fd, connector_id);
887
Oscar Mateo37f26d12013-11-12 11:50:38 +0000888 if (!connector)
889 goto err2;
890
Oscar Mateo37f26d12013-11-12 11:50:38 +0000891 if (connector->connector_id != connector_id) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200892 igt_warn("connector id doesn't match (%d != %d)\n",
893 connector->connector_id, connector_id);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000894 goto err3;
895 }
896
897 /*
898 * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
899 * In both cases find the first compatible encoder and skip the CRTC
900 * if there is non such.
901 */
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +0200902 _kmstest_connector_config_crtc_mask(drm_fd, connector, config);
Maarten Lankhorst4a185972016-06-28 14:28:20 +0200903
Maarten Lankhorste511fab2016-08-25 09:08:34 +0200904 if (!connector->count_modes)
905 memset(&config->default_mode, 0, sizeof(config->default_mode));
906 else if (!kmstest_get_connector_default_mode(drm_fd, connector,
907 &config->default_mode))
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +0200908 goto err3;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000909
910 config->connector = connector;
Maarten Lankhorst5a636682016-06-30 09:18:49 +0200911
912 crtc_idx_mask &= config->valid_crtc_idx_mask;
913 if (!crtc_idx_mask)
914 /* Keep config->connector */
915 goto err2;
916
917 config->pipe = ffs(crtc_idx_mask) - 1;
918
919 config->encoder = _kmstest_connector_config_find_encoder(drm_fd, connector, config->pipe);
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +0200920 config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[config->pipe]);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000921
Maarten Lankhorste511fab2016-08-25 09:08:34 +0200922 if (connector->connection != DRM_MODE_CONNECTED)
923 goto err2;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000924
Maarten Lankhorste511fab2016-08-25 09:08:34 +0200925 if (!connector->count_modes) {
926 igt_warn("connector %d/%s-%d has no modes\n", connector_id,
927 kmstest_connector_type_str(connector->connector_type),
928 connector->connector_type_id);
929 goto err2;
930 }
931
932 drmModeFreeResources(resources);
Daniel Vetter1cad8342014-08-12 11:57:32 +0200933 return true;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000934err3:
Maarten Lankhorst0404de42016-06-29 15:56:28 +0200935 drmModeFreeConnector(connector);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000936err2:
937 drmModeFreeResources(resources);
938err1:
Daniel Vetter1cad8342014-08-12 11:57:32 +0200939 return false;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000940}
941
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200942/**
Jesse Barnese28acef2016-01-14 14:03:53 -0800943 * kmstest_get_connector_config:
944 * @drm_fd: DRM fd
945 * @connector_id: DRM connector id
946 * @crtc_idx_mask: mask of allowed DRM CRTC indices
947 * @config: structure filled with the possible configuration
948 *
949 * This tries to find a suitable configuration for the given connector and CRTC
950 * constraint and fills it into @config.
951 */
952bool kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
953 unsigned long crtc_idx_mask,
954 struct kmstest_connector_config *config)
955{
956 return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
957 config, 0);
958}
959
960/**
961 * kmstest_probe_connector_config:
962 * @drm_fd: DRM fd
963 * @connector_id: DRM connector id
964 * @crtc_idx_mask: mask of allowed DRM CRTC indices
965 * @config: structure filled with the possible configuration
966 *
967 * This tries to find a suitable configuration for the given connector and CRTC
968 * constraint and fills it into @config, fully probing the connector in the
969 * process.
970 */
971bool kmstest_probe_connector_config(int drm_fd, uint32_t connector_id,
972 unsigned long crtc_idx_mask,
973 struct kmstest_connector_config *config)
974{
975 return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
976 config, 1);
977}
978
979/**
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200980 * kmstest_free_connector_config:
981 * @config: connector configuration structure
982 *
983 * Free any resources in @config allocated in kmstest_get_connector_config().
984 */
Oscar Mateo37f26d12013-11-12 11:50:38 +0000985void kmstest_free_connector_config(struct kmstest_connector_config *config)
986{
987 drmModeFreeCrtc(config->crtc);
Maarten Lankhorst5a636682016-06-30 09:18:49 +0200988 config->crtc = NULL;
989
Oscar Mateo37f26d12013-11-12 11:50:38 +0000990 drmModeFreeEncoder(config->encoder);
Maarten Lankhorst5a636682016-06-30 09:18:49 +0200991 config->encoder = NULL;
992
Oscar Mateo37f26d12013-11-12 11:50:38 +0000993 drmModeFreeConnector(config->connector);
Maarten Lankhorst5a636682016-06-30 09:18:49 +0200994 config->connector = NULL;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000995}
996
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200997/**
998 * kmstest_set_connector_dpms:
999 * @fd: DRM fd
1000 * @connector: libdrm connector
1001 * @mode: DRM DPMS value
1002 *
1003 * This function sets the DPMS setting of @connector to @mode.
1004 */
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001005void kmstest_set_connector_dpms(int fd, drmModeConnector *connector, int mode)
1006{
1007 int i, dpms = 0;
1008 bool found_it = false;
1009
1010 for (i = 0; i < connector->count_props; i++) {
1011 struct drm_mode_get_property prop;
1012
1013 prop.prop_id = connector->props[i];
1014 prop.count_values = 0;
1015 prop.count_enum_blobs = 0;
1016 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
1017 continue;
1018
1019 if (strcmp(prop.name, "DPMS"))
1020 continue;
1021
1022 dpms = prop.prop_id;
1023 found_it = true;
1024 break;
1025 }
1026 igt_assert_f(found_it, "DPMS property not found on %d\n",
1027 connector->connector_id);
1028
1029 igt_assert(drmModeConnectorSetProperty(fd, connector->connector_id,
1030 dpms, mode) == 0);
1031}
1032
1033/**
Lyude3bd89da2017-01-05 13:01:18 -05001034 * kmstest_set_connector_broadcast_rgb:
1035 * @fd: DRM fd
1036 * @connector: libdrm connector
1037 * @mode: Broadcast RGB mode
1038 *
1039 * This function sets the Broadcast RGB prop of @connector to @mode, if there
1040 * is one.
1041 *
1042 * Returns: true if we found and set the Broadcast RGB prop, false otherwise
1043 */
1044bool kmstest_set_connector_broadcast_rgb(int fd, drmModeConnector *connector,
1045 enum kmstest_broadcast_rgb_mode mode)
1046{
1047 uint32_t prop_id;
1048 int ret;
1049
1050 ret = kmstest_get_property(fd, connector->connector_id,
1051 DRM_MODE_OBJECT_CONNECTOR, "Broadcast RGB",
1052 &prop_id, NULL, NULL);
1053 if (!ret) {
1054 igt_debug("Broadcast RGB property not found on %d\n",
1055 connector->connector_id);
1056 return false;
1057 }
1058
1059 igt_debug("Setting Broadcast RGB mode on connector %d to %d\n",
1060 connector->connector_id, mode);
1061 ret = drmModeConnectorSetProperty(fd, connector->connector_id, prop_id,
1062 mode);
1063
1064 return ret == 0;
1065}
1066
1067/**
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001068 * kmstest_get_property:
1069 * @drm_fd: drm file descriptor
1070 * @object_id: object whose properties we're going to get
1071 * @object_type: type of obj_id (DRM_MODE_OBJECT_*)
1072 * @name: name of the property we're going to get
1073 * @prop_id: if not NULL, returns the property id
1074 * @value: if not NULL, returns the property value
1075 * @prop: if not NULL, returns the property, and the caller will have to free
1076 * it manually.
1077 *
1078 * Finds a property with the given name on the given object.
1079 *
1080 * Returns: true in case we found something.
1081 */
1082bool
1083kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type,
1084 const char *name, uint32_t *prop_id /* out */,
1085 uint64_t *value /* out */,
1086 drmModePropertyPtr *prop /* out */)
1087{
1088 drmModeObjectPropertiesPtr proplist;
1089 drmModePropertyPtr _prop;
1090 bool found = false;
1091 int i;
1092
1093 proplist = drmModeObjectGetProperties(drm_fd, object_id, object_type);
1094 for (i = 0; i < proplist->count_props; i++) {
1095 _prop = drmModeGetProperty(drm_fd, proplist->props[i]);
1096 if (!_prop)
1097 continue;
1098
1099 if (strcmp(_prop->name, name) == 0) {
1100 found = true;
1101 if (prop_id)
1102 *prop_id = proplist->props[i];
1103 if (value)
1104 *value = proplist->prop_values[i];
1105 if (prop)
1106 *prop = _prop;
1107 else
1108 drmModeFreeProperty(_prop);
1109
1110 break;
1111 }
1112 drmModeFreeProperty(_prop);
1113 }
1114
1115 drmModeFreeObjectProperties(proplist);
1116 return found;
1117}
1118
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001119struct edid_block {
1120 int pos;
1121 unsigned char *data;
1122};
1123
1124#define DTD_SUPPORTS_AUDIO 1<<6
1125
1126static struct edid_block
1127init_cea_block(const unsigned char *edid, size_t length,
1128 unsigned char *new_edid_ptr[], size_t *new_length,
1129 char extra_extensions_length,
1130 uint32_t dtd_support)
1131{
1132 struct edid_block new_edid;
1133 int n_extensions;
1134 int pos;
1135 static const char cea_header_len = 4, video_block_len = 6;
1136
1137 igt_assert(new_edid_ptr != NULL && new_length != NULL);
1138
1139 *new_length = length + 128;
1140
1141 new_edid.data = calloc(*new_length, sizeof(char));
1142 igt_assert_f(new_edid.data, "Failed to allocate %zu bytes for edid\n", sizeof(new_length));
1143 memcpy(new_edid.data, edid, length);
1144 *new_edid_ptr = new_edid.data;
1145
1146 n_extensions = new_edid.data[126];
1147 n_extensions++;
1148 new_edid.data[126] = n_extensions;
1149
1150 update_edid_csum(new_edid.data, 0);
1151
1152 /* add a cea-861 extension block */
1153 pos = length;
1154 new_edid.data[pos++] = 0x2;
1155 new_edid.data[pos++] = 0x3;
1156 new_edid.data[pos++] = cea_header_len + video_block_len +
1157 extra_extensions_length;
1158 new_edid.data[pos++] = dtd_support;
1159
1160 /* video block (id | length) */
1161 new_edid.data[pos++] = 2 << 5 | (video_block_len - 1);
1162 new_edid.data[pos++] = 32 | 0x80; /* 1080p @ 24Hz | (native)*/
1163 new_edid.data[pos++] = 5; /* 1080i @ 60Hz */
1164 new_edid.data[pos++] = 20; /* 1080i @ 50Hz */
1165 new_edid.data[pos++] = 4; /* 720p @ 60Hz*/
1166 new_edid.data[pos++] = 19; /* 720p @ 50Hz*/
1167 new_edid.pos = pos;
1168
1169 return new_edid;
1170}
1171
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001172/**
Thomas Wooda124b1a2014-07-30 11:10:49 +01001173 * kmstest_edid_add_3d:
1174 * @edid: an existing valid edid block
1175 * @length: length of @edid
1176 * @new_edid_ptr: pointer to where the new edid will be placed
1177 * @new_length: pointer to the size of the new edid
1178 *
1179 * Makes a copy of an existing edid block and adds an extension indicating
1180 * stereo 3D capabilities.
1181 */
1182void kmstest_edid_add_3d(const unsigned char *edid, size_t length,
1183 unsigned char *new_edid_ptr[], size_t *new_length)
1184{
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001185 char vsdb_block_len = 11;
1186 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1187 new_length, vsdb_block_len,
1188 0);
1189 int pos = new_edid.pos;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001190
1191 /* vsdb block ( id | length ) */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001192 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
Thomas Wooda124b1a2014-07-30 11:10:49 +01001193 /* registration id */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001194 new_edid.data[pos++] = 0x3;
1195 new_edid.data[pos++] = 0xc;
1196 new_edid.data[pos++] = 0x0;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001197 /* source physical address */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001198 new_edid.data[pos++] = 0x10;
1199 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001200 /* Supports_AI ... etc */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001201 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001202 /* Max TMDS Clock */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001203 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001204 /* Latency present, HDMI Video Present */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001205 new_edid.data[pos++] = 0x20;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001206 /* HDMI Video */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001207 new_edid.data[pos++] = 0x80;
1208 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001209
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001210 update_edid_csum(new_edid.data, length);
1211}
1212
1213/**
1214 * kmstest_edid_add_4k:
1215 * @edid: an existing valid edid block
1216 * @length: length of @edid
1217 * @new_edid_ptr: pointer to where the new edid will be placed
1218 * @new_length: pointer to the size of the new edid
1219 *
1220 * Makes a copy of an existing edid block and adds an extension indicating
1221 * a HDMI 4K mode in vsdb.
1222 */
1223void kmstest_edid_add_4k(const unsigned char *edid, size_t length,
1224 unsigned char *new_edid_ptr[], size_t *new_length)
1225{
1226 char vsdb_block_len = 12;
1227 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1228 new_length, vsdb_block_len,
1229 0);
1230 int pos = new_edid.pos;
1231
1232 /* vsdb block ( id | length ) */
1233 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
1234 /* registration id */
1235 new_edid.data[pos++] = 0x3;
1236 new_edid.data[pos++] = 0xc;
1237 new_edid.data[pos++] = 0x0;
1238 /* source physical address */
1239 new_edid.data[pos++] = 0x10;
1240 new_edid.data[pos++] = 0x00;
1241 /* Supports_AI ... etc */
1242 new_edid.data[pos++] = 0x00;
1243 /* Max TMDS Clock */
1244 new_edid.data[pos++] = 0x00;
1245 /* Latency present, HDMI Video Present */
1246 new_edid.data[pos++] = 0x20;
1247 /* HDMI Video */
1248 new_edid.data[pos++] = 0x00; /* 3D present */
1249
1250 /* HDMI MODE LEN -- how many entries */
1251 new_edid.data[pos++] = 0x20;
1252 /* 2160p, specified as short descriptor */
1253 new_edid.data[pos++] = 0x01;
1254
1255 update_edid_csum(new_edid.data, length);
1256}
1257
1258/**
1259 * kmstest_edid_add_audio:
1260 * @edid: an existing valid edid block
1261 * @length: length of @edid
1262 * @new_edid_ptr: pointer to where the new edid will be placed
1263 * @new_length: pointer to the size of the new edid
1264 *
1265 * Makes a copy of an existing edid block and adds an extension indicating
1266 * basic audio support and speaker data block.
1267 *
1268 */
1269void kmstest_edid_add_audio(const unsigned char *edid, size_t length,
1270 unsigned char *new_edid_ptr[], size_t *new_length)
1271{
1272 char vsdb_block_len = 10, audio_block_len = 4, spkr_block_len = 4;
1273 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1274 new_length,
1275 vsdb_block_len +
1276 audio_block_len +
1277 spkr_block_len,
1278 DTD_SUPPORTS_AUDIO);
1279 int pos = new_edid.pos;
1280
1281 /* audio block, short audio block descriptors */
1282 new_edid.data[pos++] = (1 << 5) | (audio_block_len - 1);
1283 new_edid.data[pos++] = 0x09; /* Audio Format, PCM */
1284 new_edid.data[pos++] = 0x07; /* Frequency, 32, 44.1, 48kHz */
1285 new_edid.data[pos++] = 0x07; /* Bit Rate 16, 20, 24 bit */
1286
1287
1288 /* vsdb block ( id | length ) -- need vsdb as well
1289 * otherwise the kernel will fallback to lower clock modes */
1290 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
1291 /* registration id */
1292 new_edid.data[pos++] = 0x3;
1293 new_edid.data[pos++] = 0xc;
1294 new_edid.data[pos++] = 0x0;
1295 /* source physical address */
1296 new_edid.data[pos++] = 0x10;
1297 new_edid.data[pos++] = 0x00;
1298 /* Supports_AI ... etc */
1299 new_edid.data[pos++] = 0x00;
1300 /* Max TMDS Clock */
1301 new_edid.data[pos++] = 0x00;
1302 /* Latency present, HDMI Video Present */
1303 new_edid.data[pos++] = 0x20;
1304 /* HDMI Video */
1305 new_edid.data[pos++] = 0x00; /* 3D present */
1306
1307 /* speaker data block */
1308 new_edid.data[pos++] = (4 << 5) | (spkr_block_len - 1);
1309 new_edid.data[pos++] = (1 << 5);
1310 new_edid.data[pos++] = 0x00;
1311 new_edid.data[pos++] = 0x00;
1312
1313 update_edid_csum(new_edid.data, length);
Thomas Wooda124b1a2014-07-30 11:10:49 +01001314}
1315
1316/**
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001317 * kmstest_unset_all_crtcs:
1318 * @drm_fd: the DRM fd
1319 * @resources: libdrm resources pointer
1320 *
1321 * Disables all the screens.
1322 */
1323void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources)
1324{
1325 int i, rc;
1326
1327 for (i = 0; i < resources->count_crtcs; i++) {
Ville Syrjälä4d8983b2015-11-11 20:25:11 +02001328 rc = drmModeSetCrtc(drm_fd, resources->crtcs[i], 0, 0, 0, NULL,
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001329 0, NULL);
1330 igt_assert(rc == 0);
1331 }
1332}
1333
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001334/**
Daniel Vetter483d1c02016-03-19 12:12:47 +01001335 * kmstest_get_crtc_idx:
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001336 * @res: the libdrm resources
1337 * @crtc_id: the CRTC id
1338 *
Daniel Vetter483d1c02016-03-19 12:12:47 +01001339 * Get the CRTC index based on its ID. This is useful since a few places of
1340 * libdrm deal with CRTC masks.
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001341 */
1342int kmstest_get_crtc_idx(drmModeRes *res, uint32_t crtc_id)
1343{
1344 int i;
1345
1346 for (i = 0; i < res->count_crtcs; i++)
1347 if (res->crtcs[i] == crtc_id)
1348 return i;
1349
1350 igt_assert(false);
1351}
1352
Mika Kahola12e34d82016-11-23 11:19:37 +02001353static inline uint32_t pipe_select(int pipe)
1354{
1355 if (pipe > 1)
1356 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
1357 else if (pipe > 0)
1358 return DRM_VBLANK_SECONDARY;
1359 else
1360 return 0;
1361}
1362
1363unsigned int kmstest_get_vblank(int fd, int pipe, unsigned int flags)
1364{
1365 union drm_wait_vblank vbl;
1366
1367 memset(&vbl, 0, sizeof(vbl));
1368 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags;
1369 if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
1370 return 0;
1371
1372 return vbl.reply.sequence;
1373}
1374
1375static void get_plane(char *str, int type, struct kmstest_plane *plane)
1376{
1377 int ret;
1378 char buf[256];
1379
Robert Foss9de63592017-01-18 12:12:54 -05001380 plane->type = type;
Mika Kahola12e34d82016-11-23 11:19:37 +02001381 ret = sscanf(str + 12, "%d%*c %*s %[^n]s",
1382 &plane->id,
1383 buf);
1384 igt_assert_eq(ret, 2);
1385
1386 ret = sscanf(buf + 9, "%4d%*c%4d%*c", &plane->pos_x, &plane->pos_y);
1387 igt_assert_eq(ret, 2);
1388
1389 ret = sscanf(buf + 30, "%4d%*c%4d%*c", &plane->width, &plane->height);
1390 igt_assert_eq(ret, 2);
1391}
1392
Robert Foss9de63592017-01-18 12:12:54 -05001393static int parse_planes(FILE *fid, struct kmstest_plane *planes)
Mika Kahola12e34d82016-11-23 11:19:37 +02001394{
1395 char tmp[256];
Robert Foss9de63592017-01-18 12:12:54 -05001396 int n_planes;
Mika Kahola12e34d82016-11-23 11:19:37 +02001397
Robert Foss9de63592017-01-18 12:12:54 -05001398 n_planes = 0;
Mika Kahola12e34d82016-11-23 11:19:37 +02001399 while (fgets(tmp, 256, fid) != NULL) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001400 if (strstr(tmp, "type=PRI") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001401 if (planes) {
1402 get_plane(tmp, DRM_PLANE_TYPE_PRIMARY, &planes[n_planes]);
1403 planes[n_planes].index = n_planes;
1404 }
1405 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001406 } else if (strstr(tmp, "type=OVL") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001407 if (planes) {
1408 get_plane(tmp, DRM_PLANE_TYPE_OVERLAY, &planes[n_planes]);
1409 planes[n_planes].index = n_planes;
1410 }
1411 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001412 } else if (strstr(tmp, "type=CUR") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001413 if (planes) {
1414 get_plane(tmp, DRM_PLANE_TYPE_CURSOR, &planes[n_planes]);
1415 planes[n_planes].index = n_planes;
1416 }
1417 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001418 break;
1419 }
1420 }
1421
Robert Foss9de63592017-01-18 12:12:54 -05001422 return n_planes;
Mika Kahola12e34d82016-11-23 11:19:37 +02001423}
1424
1425static void parse_crtc(char *info, struct kmstest_crtc *crtc)
1426{
1427 char buf[256];
1428 int ret;
1429 char pipe;
1430
1431 ret = sscanf(info + 4, "%d%*c %*s %c%*c %*s %s%*c",
1432 &crtc->id, &pipe, buf);
1433 igt_assert_eq(ret, 3);
1434
1435 crtc->pipe = kmstest_pipe_to_index(pipe);
1436 igt_assert(crtc->pipe >= 0);
1437
1438 ret = sscanf(buf + 6, "%d%*c%d%*c",
1439 &crtc->width, &crtc->height);
1440 igt_assert_eq(ret, 2);
1441}
1442
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001443void kmstest_get_crtc(int device, enum pipe pipe, struct kmstest_crtc *crtc)
Mika Kahola12e34d82016-11-23 11:19:37 +02001444{
1445 char tmp[256];
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001446 FILE *file;
Mika Kahola12e34d82016-11-23 11:19:37 +02001447 int ncrtc;
1448 int line;
Mika Kahola11e31f92017-02-16 11:20:45 +02001449 long int n;
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001450 int fd;
Mika Kahola12e34d82016-11-23 11:19:37 +02001451
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001452 fd = igt_debugfs_open(device, "i915_display_info", O_RDONLY);
1453 file = fdopen(fd, "r");
1454 igt_skip_on(file == NULL);
Mika Kahola12e34d82016-11-23 11:19:37 +02001455
1456 ncrtc = 0;
1457 line = 0;
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001458 while (fgets(tmp, 256, file) != NULL) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001459 if ((strstr(tmp, "CRTC") != NULL) && (line > 0)) {
1460 if (strstr(tmp, "active=yes") != NULL) {
1461 crtc->active = true;
1462 parse_crtc(tmp, crtc);
Robert Foss9de63592017-01-18 12:12:54 -05001463
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001464 n = ftell(file);
1465 crtc->n_planes = parse_planes(file, NULL);
Robert Foss260df252017-01-18 11:26:12 -05001466 crtc->planes = calloc(crtc->n_planes, sizeof(*crtc->planes));
1467 igt_assert_f(crtc->planes, "Failed to allocate memory for %d planes\n", crtc->n_planes);
1468
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001469 fseek(file, n, SEEK_SET);
1470 parse_planes(file, crtc->planes);
Mika Kahola12e34d82016-11-23 11:19:37 +02001471
Mika Kahola11e31f92017-02-16 11:20:45 +02001472 if (crtc->pipe != pipe) {
1473 free(crtc->planes);
1474 } else {
Mika Kahola12e34d82016-11-23 11:19:37 +02001475 ncrtc++;
Mika Kahola11e31f92017-02-16 11:20:45 +02001476 break;
1477 }
Mika Kahola12e34d82016-11-23 11:19:37 +02001478 }
1479 }
1480
1481 line++;
1482 }
1483
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001484 fclose(file);
1485 close(fd);
Mika Kahola12e34d82016-11-23 11:19:37 +02001486
1487 igt_skip_on(ncrtc == 0);
1488}
1489
Chris Wilson83884e92017-03-21 17:16:03 +00001490void igt_assert_plane_visible(int fd, enum pipe pipe, bool visibility)
Mika Kahola12e34d82016-11-23 11:19:37 +02001491{
1492 struct kmstest_crtc crtc;
1493 int i;
1494 bool visible;
1495
Chris Wilson83884e92017-03-21 17:16:03 +00001496 kmstest_get_crtc(fd, pipe, &crtc);
Mika Kahola12e34d82016-11-23 11:19:37 +02001497
1498 visible = true;
Robert Foss260df252017-01-18 11:26:12 -05001499 for (i = 0; i < crtc.n_planes; i++) {
1500 if (crtc.planes[i].type == DRM_PLANE_TYPE_PRIMARY)
Robert Foss9de63592017-01-18 12:12:54 -05001501 continue;
1502
Robert Foss260df252017-01-18 11:26:12 -05001503 if (crtc.planes[i].pos_x > crtc.width) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001504 visible = false;
1505 break;
Robert Foss260df252017-01-18 11:26:12 -05001506 } else if (crtc.planes[i].pos_y > crtc.height) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001507 visible = false;
1508 break;
1509 }
1510 }
1511
1512 igt_assert_eq(visible, visibility);
1513}
1514
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001515/*
1516 * A small modeset API
1517 */
1518
1519#define LOG_SPACES " "
1520#define LOG_N_SPACES (sizeof(LOG_SPACES) - 1)
1521
1522#define LOG_INDENT(d, section) \
1523 do { \
1524 igt_display_log(d, "%s {\n", section); \
1525 igt_display_log_shift(d, 1); \
1526 } while (0)
1527#define LOG_UNINDENT(d) \
1528 do { \
1529 igt_display_log_shift(d, -1); \
1530 igt_display_log(d, "}\n"); \
1531 } while (0)
1532#define LOG(d, fmt, ...) igt_display_log(d, fmt, ## __VA_ARGS__)
1533
Daniel Vetterbd53d722014-03-13 17:27:47 +01001534static void __attribute__((format(printf, 2, 3)))
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001535igt_display_log(igt_display_t *display, const char *fmt, ...)
1536{
1537 va_list args;
Daniel Vetterbd53d722014-03-13 17:27:47 +01001538 int i;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001539
1540 va_start(args, fmt);
Daniel Vetterbd53d722014-03-13 17:27:47 +01001541 igt_debug("display: ");
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001542 for (i = 0; i < display->log_shift; i++)
Daniel Vetterbd53d722014-03-13 17:27:47 +01001543 igt_debug("%s", LOG_SPACES);
Thomas Wood8161a212014-12-02 10:54:54 +00001544 igt_vlog(IGT_LOG_DOMAIN, IGT_LOG_DEBUG, fmt, args);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001545 va_end(args);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001546}
1547
1548static void igt_display_log_shift(igt_display_t *display, int shift)
1549{
1550 display->log_shift += shift;
1551 igt_assert(display->log_shift >= 0);
1552}
1553
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001554static void igt_output_refresh(igt_output_t *output)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001555{
1556 igt_display_t *display = output->display;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001557 unsigned long crtc_idx_mask;
1558
Maarten Lankhorstd8518f32016-10-05 13:39:29 +02001559 crtc_idx_mask = output->pending_crtc_idx_mask;
1560
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001561 kmstest_free_connector_config(&output->config);
Daniel Vetter1cad8342014-08-12 11:57:32 +02001562
Maarten Lankhorstba237f92017-01-10 10:50:50 +01001563 _kmstest_connector_config(display->drm_fd, output->id, crtc_idx_mask,
1564 &output->config, output->force_reprobe);
1565 output->force_reprobe = false;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001566
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001567 if (!output->name && output->config.connector) {
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001568 drmModeConnector *c = output->config.connector;
1569
Thomas Wood47f6b132015-03-25 16:42:57 +00001570 igt_assert_neq(asprintf(&output->name, "%s-%d", kmstest_connector_type_str(c->connector_type), c->connector_type_id),
1571 -1);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001572 }
1573
Petri Latvalac9c043d2017-05-10 12:22:38 +03001574 if (output->config.connector) {
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001575 igt_atomic_fill_connector_props(display, output,
1576 IGT_NUM_CONNECTOR_PROPS, igt_connector_prop_names);
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02001577
Petri Latvalac9c043d2017-05-10 12:22:38 +03001578 kmstest_set_connector_broadcast_rgb(display->drm_fd,
1579 output->config.connector,
1580 BROADCAST_RGB_FULL);
1581 }
1582
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001583 if (output->use_override_mode)
1584 output->config.default_mode = output->override_mode;
1585
Maarten Lankhorstba237f92017-01-10 10:50:50 +01001586 if (output->config.pipe == PIPE_NONE)
1587 return;
1588
Daniel Vetterdd8fba42014-08-12 11:00:37 +02001589 LOG(display, "%s: Selecting pipe %s\n", output->name,
1590 kmstest_pipe_name(output->config.pipe));
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001591}
1592
Damien Lespiau143c3a72014-07-08 14:56:54 +01001593static bool
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001594get_plane_property(int drm_fd, uint32_t plane_id, const char *name,
Paulo Zanoni053c1042014-08-06 12:03:57 -03001595 uint32_t *prop_id /* out */, uint64_t *value /* out */,
1596 drmModePropertyPtr *prop /* out */)
Damien Lespiau143c3a72014-07-08 14:56:54 +01001597{
Paulo Zanoni4924b782014-08-06 12:14:56 -03001598 return kmstest_get_property(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE,
1599 name, prop_id, value, prop);
Damien Lespiau143c3a72014-07-08 14:56:54 +01001600}
1601
Sonika Jindal7ef80c02015-04-07 13:59:03 +05301602static int
Damien Lespiau068efd82014-07-08 16:02:05 +01001603igt_plane_set_property(igt_plane_t *plane, uint32_t prop_id, uint64_t value)
1604{
1605 igt_pipe_t *pipe = plane->pipe;
1606 igt_display_t *display = pipe->display;
1607
Sonika Jindal7ef80c02015-04-07 13:59:03 +05301608 return drmModeObjectSetProperty(display->drm_fd, plane->drm_plane->plane_id,
Damien Lespiau068efd82014-07-08 16:02:05 +01001609 DRM_MODE_OBJECT_PLANE, prop_id, value);
1610}
1611
chandra konduruace42082015-03-30 13:44:32 -07001612static bool
1613get_crtc_property(int drm_fd, uint32_t crtc_id, const char *name,
1614 uint32_t *prop_id /* out */, uint64_t *value /* out */,
1615 drmModePropertyPtr *prop /* out */)
1616{
1617 return kmstest_get_property(drm_fd, crtc_id, DRM_MODE_OBJECT_CRTC,
1618 name, prop_id, value, prop);
1619}
1620
1621static void
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02001622igt_crtc_set_property(igt_pipe_t *pipe, uint32_t prop_id, uint64_t value)
chandra konduruace42082015-03-30 13:44:32 -07001623{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02001624 drmModeObjectSetProperty(pipe->display->drm_fd,
1625 pipe->crtc_id, DRM_MODE_OBJECT_CRTC, prop_id, value);
chandra konduruace42082015-03-30 13:44:32 -07001626}
1627
Matt Roper794a9fd2014-06-30 16:44:26 -07001628/*
1629 * Walk a plane's property list to determine its type. If we don't
1630 * find a type property, then the kernel doesn't support universal
1631 * planes and we know the plane is an overlay/sprite.
1632 */
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001633static int get_drm_plane_type(int drm_fd, uint32_t plane_id)
Matt Roper794a9fd2014-06-30 16:44:26 -07001634{
Damien Lespiau33842d52014-07-08 14:34:16 +01001635 uint64_t value;
1636 bool has_prop;
Matt Roper794a9fd2014-06-30 16:44:26 -07001637
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001638 has_prop = get_plane_property(drm_fd, plane_id, "type",
Paulo Zanoni053c1042014-08-06 12:03:57 -03001639 NULL /* prop_id */, &value, NULL);
Damien Lespiau33842d52014-07-08 14:34:16 +01001640 if (has_prop)
1641 return (int)value;
Matt Roper794a9fd2014-06-30 16:44:26 -07001642
Damien Lespiau33842d52014-07-08 14:34:16 +01001643 return DRM_PLANE_TYPE_OVERLAY;
Matt Roper794a9fd2014-06-30 16:44:26 -07001644}
1645
Thomas Wood2e5a43d2015-11-02 15:48:52 +00001646/**
1647 * igt_display_init:
1648 * @display: a pointer to an #igt_display_t structure
1649 * @drm_fd: a drm file descriptor
1650 *
1651 * Initialize @display and allocate the various resources required. Use
1652 * #igt_display_fini to release the resources when they are no longer required.
1653 *
1654 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001655void igt_display_init(igt_display_t *display, int drm_fd)
1656{
1657 drmModeRes *resources;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001658 drmModePlaneRes *plane_resources;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001659 int i;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05301660 int is_atomic = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001661
Thomas Wood5874dad2014-06-16 16:12:21 +01001662 memset(display, 0, sizeof(igt_display_t));
1663
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001664 LOG_INDENT(display, "init");
1665
1666 display->drm_fd = drm_fd;
1667
1668 resources = drmModeGetResources(display->drm_fd);
1669 igt_assert(resources);
1670
1671 /*
1672 * We cache the number of pipes, that number is a physical limit of the
1673 * hardware and cannot change of time (for now, at least).
1674 */
1675 display->n_pipes = resources->count_crtcs;
Lyude3ccce992016-12-12 13:25:39 -05001676 display->pipes = calloc(sizeof(igt_pipe_t), display->n_pipes);
Robert Foss725edb32017-01-18 10:15:24 -05001677 igt_assert_f(display->pipes, "Failed to allocate memory for %d pipes\n", display->n_pipes);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001678
Matt Roper794a9fd2014-06-30 16:44:26 -07001679 drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05301680 is_atomic = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001681 plane_resources = drmModeGetPlaneResources(display->drm_fd);
1682 igt_assert(plane_resources);
1683
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001684 for (i = 0; i < display->n_pipes; i++) {
1685 igt_pipe_t *pipe = &display->pipes[i];
1686 igt_plane_t *plane;
Robert Foss36656232017-01-18 12:28:45 -05001687 int p = 1;
Matt Roper794a9fd2014-06-30 16:44:26 -07001688 int j, type;
Robert Foss36656232017-01-18 12:28:45 -05001689 uint8_t last_plane = 0, n_planes = 0;
Maarten Lankhorsta8e23212016-07-25 15:14:54 +02001690 uint64_t prop_value;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001691
Lionel Landwerlin59b54872016-03-18 17:33:00 +00001692 pipe->crtc_id = resources->crtcs[i];
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001693 pipe->display = display;
1694 pipe->pipe = i;
Robert Foss36656232017-01-18 12:28:45 -05001695 pipe->plane_cursor = -1;
1696 pipe->plane_primary = -1;
1697 pipe->planes = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001698
Maarten Lankhorsta8e23212016-07-25 15:14:54 +02001699 get_crtc_property(display->drm_fd, pipe->crtc_id,
1700 "background_color",
1701 &pipe->background_property,
1702 &prop_value,
1703 NULL);
1704 pipe->background = (uint32_t)prop_value;
1705 get_crtc_property(display->drm_fd, pipe->crtc_id,
1706 "DEGAMMA_LUT",
1707 &pipe->degamma_property,
1708 NULL,
1709 NULL);
1710 get_crtc_property(display->drm_fd, pipe->crtc_id,
1711 "CTM",
1712 &pipe->ctm_property,
1713 NULL,
1714 NULL);
1715 get_crtc_property(display->drm_fd, pipe->crtc_id,
1716 "GAMMA_LUT",
1717 &pipe->gamma_property,
1718 NULL,
1719 NULL);
1720
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02001721 igt_atomic_fill_pipe_props(display, pipe, IGT_NUM_CRTC_PROPS, igt_crtc_prop_names);
1722
Robert Foss36656232017-01-18 12:28:45 -05001723 /* count number of valid planes */
1724 for (j = 0; j < plane_resources->count_planes; j++) {
1725 drmModePlane *drm_plane;
1726
1727 drm_plane = drmModeGetPlane(display->drm_fd,
1728 plane_resources->planes[j]);
1729 igt_assert(drm_plane);
1730
Brian Starkey4cb80db2017-02-20 11:02:44 +00001731 if (drm_plane->possible_crtcs & (1 << i))
1732 n_planes++;
Robert Foss36656232017-01-18 12:28:45 -05001733
Brian Starkey4cb80db2017-02-20 11:02:44 +00001734 drmModeFreePlane(drm_plane);
Robert Foss36656232017-01-18 12:28:45 -05001735 }
1736
1737 igt_assert_lte(0, n_planes);
1738 pipe->planes = calloc(sizeof(igt_plane_t), n_planes);
1739 igt_assert_f(pipe->planes, "Failed to allocate memory for %d planes\n", n_planes);
1740 last_plane = n_planes - 1;
1741
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001742 /* add the planes that can be used with that pipe */
1743 for (j = 0; j < plane_resources->count_planes; j++) {
1744 drmModePlane *drm_plane;
1745
1746 drm_plane = drmModeGetPlane(display->drm_fd,
1747 plane_resources->planes[j]);
1748 igt_assert(drm_plane);
1749
1750 if (!(drm_plane->possible_crtcs & (1 << i))) {
1751 drmModeFreePlane(drm_plane);
1752 continue;
1753 }
1754
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001755 type = get_drm_plane_type(display->drm_fd,
Matt Roper794a9fd2014-06-30 16:44:26 -07001756 plane_resources->planes[j]);
Brian Starkey1ab629f2017-02-20 11:02:45 +00001757
1758 if (type == DRM_PLANE_TYPE_PRIMARY && pipe->plane_primary == -1) {
1759 plane = &pipe->planes[0];
1760 plane->index = 0;
1761 pipe->plane_primary = 0;
1762 } else if (type == DRM_PLANE_TYPE_CURSOR && pipe->plane_cursor == -1) {
1763 plane = &pipe->planes[last_plane];
1764 plane->index = last_plane;
1765 pipe->plane_cursor = last_plane;
Lyude80baeb02016-12-07 19:02:04 -05001766 display->has_cursor_plane = true;
Brian Starkey1ab629f2017-02-20 11:02:45 +00001767 } else {
Matt Roper794a9fd2014-06-30 16:44:26 -07001768 plane = &pipe->planes[p];
1769 plane->index = p++;
Matt Roper794a9fd2014-06-30 16:44:26 -07001770 }
1771
Robert Foss36656232017-01-18 12:28:45 -05001772 igt_assert_f(plane->index < n_planes, "n_planes < plane->index failed\n");
1773 plane->type = type;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001774 plane->pipe = pipe;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001775 plane->drm_plane = drm_plane;
Robert Foss221848d2016-06-20 10:24:08 -04001776 plane->fence_fd = -1;
Robert Foss235ff7a2016-05-18 20:07:04 -04001777
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05301778 if (is_atomic == 0) {
1779 display->is_atomic = 1;
1780 igt_atomic_fill_plane_props(display, plane, IGT_NUM_PLANE_PROPS, igt_plane_prop_names);
1781 }
Damien Lespiaub2eb4852014-07-08 15:23:05 +01001782
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001783 get_plane_property(display->drm_fd, drm_plane->plane_id,
Damien Lespiaub2eb4852014-07-08 15:23:05 +01001784 "rotation",
1785 &plane->rotation_property,
Paulo Zanoni053c1042014-08-06 12:03:57 -03001786 &prop_value,
1787 NULL);
Damien Lespiaub2eb4852014-07-08 15:23:05 +01001788 plane->rotation = (igt_rotation_t)prop_value;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001789 }
1790
Lyude80baeb02016-12-07 19:02:04 -05001791 /*
1792 * At the bare minimum, we should expect to have a primary
Brian Starkey45f9bb42017-02-20 11:02:46 +00001793 * plane, and it must be in slot 0.
Lyude80baeb02016-12-07 19:02:04 -05001794 */
Brian Starkey45f9bb42017-02-20 11:02:46 +00001795 igt_assert_eq(pipe->plane_primary, 0);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00001796
Brian Starkeybf2a1032017-06-05 14:28:37 +01001797 /* Check that we filled every slot exactly once */
1798 if (display->has_cursor_plane)
1799 igt_assert_eq(p, last_plane);
1800 else
1801 igt_assert_eq(p, n_planes);
Matt Roper794a9fd2014-06-30 16:44:26 -07001802
Robert Foss235ff7a2016-05-18 20:07:04 -04001803 pipe->n_planes = n_planes;
Damien Lespiau5ec399b2014-02-05 16:36:51 +00001804
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001805 for_each_plane_on_pipe(display, i, plane)
1806 plane->fb_changed = true;
1807
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001808 pipe->mode_changed = true;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001809 }
1810
1811 /*
1812 * The number of connectors is set, so we just initialize the outputs
1813 * array in _init(). This may change when we need dynamic connectors
1814 * (say DisplayPort MST).
1815 */
1816 display->n_outputs = resources->count_connectors;
1817 display->outputs = calloc(display->n_outputs, sizeof(igt_output_t));
Robert Foss725edb32017-01-18 10:15:24 -05001818 igt_assert_f(display->outputs, "Failed to allocate memory for %d outputs\n", display->n_outputs);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001819
1820 for (i = 0; i < display->n_outputs; i++) {
1821 igt_output_t *output = &display->outputs[i];
1822
1823 /*
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001824 * We don't assign each output a pipe unless
1825 * a pipe is set with igt_output_set_pipe().
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001826 */
Maarten Lankhorstba237f92017-01-10 10:50:50 +01001827 output->force_reprobe = true;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001828 output->pending_crtc_idx_mask = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001829 output->id = resources->connectors[i];
1830 output->display = display;
1831
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001832 igt_output_refresh(output);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001833
1834 output->config.pipe_changed = true;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001835 }
1836
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001837 drmModeFreePlaneResources(plane_resources);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001838 drmModeFreeResources(resources);
1839
1840 LOG_UNINDENT(display);
1841}
1842
Damien Lespiau72e9a6c2014-02-04 14:59:39 +00001843int igt_display_get_n_pipes(igt_display_t *display)
1844{
1845 return display->n_pipes;
1846}
1847
Maarten Lankhorst0b8933d2017-06-12 11:03:22 +02001848void igt_display_require_output(igt_display_t *display)
1849{
1850 enum pipe pipe;
1851 igt_output_t *output;
1852
1853 for_each_pipe_with_valid_output(display, pipe, output)
1854 return;
1855
1856 igt_skip("No valid crtc/connector combinations found.\n");
1857}
1858
1859void igt_display_require_output_on_pipe(igt_display_t *display, enum pipe pipe)
1860{
1861 igt_output_t *output;
1862
1863 igt_skip_on_f(igt_display_get_n_pipes(display) < pipe,
1864 "Pipe %s does not exist.\n", kmstest_pipe_name(pipe));
1865
1866 for_each_valid_output_on_pipe(display, pipe, output)
1867 return;
1868
1869 igt_skip("No valid connector found on pipe %s\n", kmstest_pipe_name(pipe));
1870}
1871
Lyude528cdaf2016-12-29 19:25:31 -05001872/**
1873 * igt_output_from_connector:
1874 * @display: a pointer to an #igt_display_t structure
1875 * @connector: a pointer to a drmModeConnector
1876 *
1877 * Finds the output corresponding to the given connector
1878 *
1879 * Returns: A #igt_output_t structure configured to use the connector, or NULL
1880 * if none was found
1881 */
1882igt_output_t *igt_output_from_connector(igt_display_t *display,
1883 drmModeConnector *connector)
1884{
1885 igt_output_t *output, *found = NULL;
1886
1887 for_each_connected_output(display, output) {
1888 if (output->config.connector->connector_id ==
1889 connector->connector_id) {
1890 found = output;
1891 break;
1892 }
1893 }
1894
1895 return found;
1896}
1897
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001898static void igt_pipe_fini(igt_pipe_t *pipe)
1899{
1900 int i;
1901
1902 for (i = 0; i < pipe->n_planes; i++) {
1903 igt_plane_t *plane = &pipe->planes[i];
1904
1905 if (plane->drm_plane) {
1906 drmModeFreePlane(plane->drm_plane);
1907 plane->drm_plane = NULL;
1908 }
1909 }
Robert Foss36656232017-01-18 12:28:45 -05001910
1911 free(pipe->planes);
1912 pipe->planes = NULL;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001913}
1914
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001915static void igt_output_fini(igt_output_t *output)
1916{
Maarten Lankhorstba237f92017-01-10 10:50:50 +01001917 kmstest_free_connector_config(&output->config);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001918 free(output->name);
Robert Foss900f1d42017-01-16 10:53:58 -05001919 output->name = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001920}
1921
Thomas Wood2e5a43d2015-11-02 15:48:52 +00001922/**
1923 * igt_display_fini:
1924 * @display: a pointer to an #igt_display_t structure
1925 *
1926 * Release any resources associated with @display. This does not free @display
1927 * itself.
1928 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001929void igt_display_fini(igt_display_t *display)
1930{
1931 int i;
1932
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001933 for (i = 0; i < display->n_pipes; i++)
1934 igt_pipe_fini(&display->pipes[i]);
1935
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001936 for (i = 0; i < display->n_outputs; i++)
1937 igt_output_fini(&display->outputs[i]);
1938 free(display->outputs);
1939 display->outputs = NULL;
Robert Foss900f1d42017-01-16 10:53:58 -05001940 free(display->pipes);
1941 display->pipes = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001942}
1943
1944static void igt_display_refresh(igt_display_t *display)
1945{
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001946 igt_output_t *output;
1947 int i;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001948
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001949 unsigned long pipes_in_use = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001950
Damien Lespiau162914b2014-02-06 16:05:19 +00001951 /* Check that two outputs aren't trying to use the same pipe */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001952 for (i = 0; i < display->n_outputs; i++) {
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001953 output = &display->outputs[i];
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001954
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001955 if (pipes_in_use & output->pending_crtc_idx_mask)
1956 goto report_dup;
1957
1958 pipes_in_use |= output->pending_crtc_idx_mask;
1959
1960 if (output->force_reprobe)
1961 igt_output_refresh(output);
1962 }
1963
1964 return;
1965
1966report_dup:
1967 for (; i > 0; i--) {
1968 igt_output_t *b = &display->outputs[i - 1];
1969
1970 igt_assert_f(output->pending_crtc_idx_mask !=
1971 b->pending_crtc_idx_mask,
1972 "%s and %s are both trying to use pipe %s\n",
1973 igt_output_name(output), igt_output_name(b),
1974 kmstest_pipe_name(ffs(b->pending_crtc_idx_mask) - 1));
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001975 }
1976}
1977
1978static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
1979{
1980 igt_display_t *display = output->display;
1981 enum pipe pipe;
1982
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001983 if (!output->pending_crtc_idx_mask) {
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001984 /*
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001985 * The user hasn't specified a pipe to use, return none.
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001986 */
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001987 return NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001988 } else {
1989 /*
1990 * Otherwise, return the pending pipe (ie the pipe that should
1991 * drive this output after the commit()
1992 */
1993 pipe = ffs(output->pending_crtc_idx_mask) - 1;
1994 }
1995
1996 igt_assert(pipe >= 0 && pipe < display->n_pipes);
1997
1998 return &display->pipes[pipe];
1999}
2000
Robert Foss36656232017-01-18 12:28:45 -05002001static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int plane_idx)
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002002{
Robert Foss36656232017-01-18 12:28:45 -05002003 igt_assert_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2004 "Valid pipe->planes plane_idx not found, plane_idx=%d n_planes=%d",
2005 plane_idx, pipe->n_planes);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002006
Robert Foss36656232017-01-18 12:28:45 -05002007 return &pipe->planes[plane_idx];
2008}
2009
2010
2011igt_plane_t *igt_pipe_get_plane_type(igt_pipe_t *pipe, int plane_type)
2012{
2013 int i, plane_idx = -1;
2014
2015 switch(plane_type) {
2016 case DRM_PLANE_TYPE_CURSOR:
2017 plane_idx = pipe->plane_cursor;
2018 break;
2019 case DRM_PLANE_TYPE_PRIMARY:
2020 plane_idx = pipe->plane_primary;
2021 break;
2022 case DRM_PLANE_TYPE_OVERLAY:
2023 for(i = 0; i < pipe->n_planes; i++)
2024 if (pipe->planes[i].type == DRM_PLANE_TYPE_OVERLAY)
2025 plane_idx = i;
2026 break;
2027 default:
2028 break;
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002029 }
2030
Robert Foss36656232017-01-18 12:28:45 -05002031 igt_assert_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2032 "Valid pipe->planes idx not found. plane_idx=%d plane_type=%d n_planes=%d\n",
2033 plane_idx, plane_type, pipe->n_planes);
2034
2035 return &pipe->planes[plane_idx];
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002036}
2037
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002038static igt_output_t *igt_pipe_get_output(igt_pipe_t *pipe)
2039{
2040 igt_display_t *display = pipe->display;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002041 int i;
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002042
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002043 for (i = 0; i < display->n_outputs; i++) {
2044 igt_output_t *output = &display->outputs[i];
2045
2046 if (output->pending_crtc_idx_mask == (1 << pipe->pipe))
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002047 return output;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002048 }
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002049
2050 return NULL;
2051}
2052
Lionel Landwerlin17166252016-03-18 17:33:01 +00002053bool igt_pipe_get_property(igt_pipe_t *pipe, const char *name,
2054 uint32_t *prop_id, uint64_t *value,
2055 drmModePropertyPtr *prop)
2056{
2057 return get_crtc_property(pipe->display->drm_fd,
2058 pipe->crtc_id,
2059 name,
2060 prop_id, value, prop);
2061}
2062
Damien Lespiaub4e85b72014-02-11 17:53:00 +00002063static uint32_t igt_plane_get_fb_id(igt_plane_t *plane)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002064{
2065 if (plane->fb)
2066 return plane->fb->fb_id;
2067 else
2068 return 0;
2069}
2070
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002071static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane)
2072{
2073 if (plane->fb)
2074 return plane->fb->gem_handle;
2075 else
2076 return 0;
2077}
2078
Matt Roper82bc03f2014-06-30 16:44:25 -07002079#define CHECK_RETURN(r, fail) { \
2080 if (r && !fail) \
2081 return r; \
Tomeu Vizoso1e6fc782016-12-06 15:41:26 +01002082 igt_assert_eq(r, 0); \
Matt Roper82bc03f2014-06-30 16:44:25 -07002083}
2084
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302085
2086
2087
2088/*
2089 * Add position and fb changes of a plane to the atomic property set
2090 */
2091static void
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002092igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302093 drmModeAtomicReq *req)
2094{
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002095 igt_display_t *display = pipe->display;
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002096 uint32_t fb_id, crtc_id;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302097
2098 igt_assert(plane->drm_plane);
2099
2100 /* it's an error to try an unsupported feature */
2101 igt_assert(igt_plane_supports_rotation(plane) ||
2102 !plane->rotation_changed);
2103
2104 fb_id = igt_plane_get_fb_id(plane);
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002105 crtc_id = pipe->crtc_id;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302106
2107 LOG(display,
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002108 "populating plane data: %s.%d, fb %u\n",
2109 kmstest_pipe_name(pipe->pipe),
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302110 plane->index,
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002111 fb_id);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302112
Robert Foss221848d2016-06-20 10:24:08 -04002113 if (plane->fence_fd >= 0) {
2114 uint64_t fence_fd = (int64_t) plane->fence_fd;
2115 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_IN_FENCE_FD, fence_fd);
2116 }
2117
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302118 if (plane->fb_changed) {
2119 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_ID, fb_id ? crtc_id : 0);
2120 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_FB_ID, fb_id);
2121 }
2122
2123 if (plane->position_changed || plane->size_changed) {
Lionel Landwerlincd8da3f2016-04-05 14:13:53 +01002124 uint32_t src_x = IGT_FIXED(plane->src_x, 0); /* src_x */
2125 uint32_t src_y = IGT_FIXED(plane->src_y, 0); /* src_y */
2126 uint32_t src_w = IGT_FIXED(plane->src_w, 0); /* src_w */
2127 uint32_t src_h = IGT_FIXED(plane->src_h, 0); /* src_h */
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302128 int32_t crtc_x = plane->crtc_x;
2129 int32_t crtc_y = plane->crtc_y;
2130 uint32_t crtc_w = plane->crtc_w;
2131 uint32_t crtc_h = plane->crtc_h;
2132
2133 LOG(display,
2134 "src = (%d, %d) %u x %u "
2135 "dst = (%d, %d) %u x %u\n",
2136 src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
2137 crtc_x, crtc_y, crtc_w, crtc_h);
2138
2139 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_X, src_x);
2140 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_Y, src_y);
2141 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_W, src_w);
2142 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_H, src_h);
2143
2144 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_X, crtc_x);
2145 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_Y, crtc_y);
2146 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_W, crtc_w);
2147 igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_H, crtc_h);
2148 }
2149
2150 if (plane->rotation_changed)
2151 igt_atomic_populate_plane_req(req, plane,
2152 IGT_PLANE_ROTATION, plane->rotation);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302153}
2154
2155
2156
Matt Roper82bc03f2014-06-30 16:44:25 -07002157/*
2158 * Commit position and fb changes to a DRM plane via the SetPlane ioctl; if the
2159 * DRM call to program the plane fails, we'll either fail immediately (for
2160 * tests that expect the commit to succeed) or return the failure code (for
2161 * tests that expect a specific error code).
2162 */
2163static int igt_drm_plane_commit(igt_plane_t *plane,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002164 igt_pipe_t *pipe,
Matt Roper82bc03f2014-06-30 16:44:25 -07002165 bool fail_on_error)
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002166{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002167 igt_display_t *display = pipe->display;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002168 uint32_t fb_id, crtc_id;
2169 int ret;
chandra kondurua26f9f92015-03-30 13:52:04 -07002170 uint32_t src_x;
2171 uint32_t src_y;
2172 uint32_t src_w;
2173 uint32_t src_h;
2174 int32_t crtc_x;
2175 int32_t crtc_y;
2176 uint32_t crtc_w;
2177 uint32_t crtc_h;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002178
Matt Roper794a9fd2014-06-30 16:44:26 -07002179 igt_assert(plane->drm_plane);
2180
Damien Lespiau068efd82014-07-08 16:02:05 +01002181 /* it's an error to try an unsupported feature */
2182 igt_assert(igt_plane_supports_rotation(plane) ||
2183 !plane->rotation_changed);
2184
Damien Lespiaub4e85b72014-02-11 17:53:00 +00002185 fb_id = igt_plane_get_fb_id(plane);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002186 crtc_id = pipe->crtc_id;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002187
Tvrtko Ursulin759bb7a2015-05-12 11:06:35 +01002188 if ((plane->fb_changed || plane->size_changed) && fb_id == 0) {
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002189 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002190 "SetPlane pipe %s, plane %d, disabling\n",
2191 kmstest_pipe_name(pipe->pipe),
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002192 plane->index);
2193
2194 ret = drmModeSetPlane(display->drm_fd,
2195 plane->drm_plane->plane_id,
2196 crtc_id,
2197 fb_id,
2198 0, /* flags */
2199 0, 0, /* crtc_x, crtc_y */
2200 0, 0, /* crtc_w, crtc_h */
2201 IGT_FIXED(0,0), /* src_x */
2202 IGT_FIXED(0,0), /* src_y */
2203 IGT_FIXED(0,0), /* src_w */
2204 IGT_FIXED(0,0) /* src_h */);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002205
Matt Roper794a9fd2014-06-30 16:44:26 -07002206 CHECK_RETURN(ret, fail_on_error);
chandra kondurua26f9f92015-03-30 13:52:04 -07002207 } else if (plane->fb_changed || plane->position_changed ||
2208 plane->size_changed) {
Lionel Landwerlincd8da3f2016-04-05 14:13:53 +01002209 src_x = IGT_FIXED(plane->src_x,0); /* src_x */
2210 src_y = IGT_FIXED(plane->src_y,0); /* src_y */
2211 src_w = IGT_FIXED(plane->src_w,0); /* src_w */
2212 src_h = IGT_FIXED(plane->src_h,0); /* src_h */
chandra kondurua26f9f92015-03-30 13:52:04 -07002213 crtc_x = plane->crtc_x;
2214 crtc_y = plane->crtc_y;
2215 crtc_w = plane->crtc_w;
2216 crtc_h = plane->crtc_h;
2217
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002218 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002219 "SetPlane %s.%d, fb %u, src = (%d, %d) "
chandra kondurua26f9f92015-03-30 13:52:04 -07002220 "%ux%u dst = (%u, %u) %ux%u\n",
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002221 kmstest_pipe_name(pipe->pipe),
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002222 plane->index,
2223 fb_id,
chandra kondurua26f9f92015-03-30 13:52:04 -07002224 src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
2225 crtc_x, crtc_y, crtc_w, crtc_h);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002226
2227 ret = drmModeSetPlane(display->drm_fd,
2228 plane->drm_plane->plane_id,
2229 crtc_id,
2230 fb_id,
2231 0, /* flags */
chandra kondurua26f9f92015-03-30 13:52:04 -07002232 crtc_x, crtc_y,
2233 crtc_w, crtc_h,
2234 src_x, src_y,
2235 src_w, src_h);
Matt Roper794a9fd2014-06-30 16:44:26 -07002236
Matt Roper82bc03f2014-06-30 16:44:25 -07002237 CHECK_RETURN(ret, fail_on_error);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002238 }
2239
Damien Lespiau068efd82014-07-08 16:02:05 +01002240 if (plane->rotation_changed) {
Sonika Jindal7ef80c02015-04-07 13:59:03 +05302241 ret = igt_plane_set_property(plane, plane->rotation_property,
Damien Lespiau068efd82014-07-08 16:02:05 +01002242 plane->rotation);
2243
Sonika Jindal7ef80c02015-04-07 13:59:03 +05302244 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau068efd82014-07-08 16:02:05 +01002245 }
2246
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002247 return 0;
2248}
2249
Matt Roper794a9fd2014-06-30 16:44:26 -07002250/*
2251 * Commit position and fb changes to a cursor via legacy ioctl's. If commit
2252 * fails, we'll either fail immediately (for tests that expect the commit to
2253 * succeed) or return the failure code (for tests that expect a specific error
2254 * code).
2255 */
2256static int igt_cursor_commit_legacy(igt_plane_t *cursor,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002257 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002258 bool fail_on_error)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002259{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002260 igt_display_t *display = pipe->display;
2261 uint32_t crtc_id = pipe->crtc_id;
Matt Roper794a9fd2014-06-30 16:44:26 -07002262 int ret;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002263
Matt Roper3cc60ba2014-06-30 16:44:22 -07002264 if (cursor->fb_changed) {
Matt Roper794a9fd2014-06-30 16:44:26 -07002265 uint32_t gem_handle = igt_plane_get_fb_gem_handle(cursor);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002266
2267 if (gem_handle) {
2268 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002269 "SetCursor pipe %s, fb %u %dx%d\n",
2270 kmstest_pipe_name(pipe->pipe),
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002271 gem_handle,
Ville Syrjälä7b767542014-09-12 20:18:04 +03002272 cursor->crtc_w, cursor->crtc_h);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002273
2274 ret = drmModeSetCursor(display->drm_fd, crtc_id,
2275 gem_handle,
Ville Syrjälä7b767542014-09-12 20:18:04 +03002276 cursor->crtc_w,
2277 cursor->crtc_h);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002278 } else {
2279 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002280 "SetCursor pipe %s, disabling\n",
2281 kmstest_pipe_name(pipe->pipe));
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002282
2283 ret = drmModeSetCursor(display->drm_fd, crtc_id,
2284 0, 0, 0);
2285 }
Matt Roper794a9fd2014-06-30 16:44:26 -07002286
Matt Roper82bc03f2014-06-30 16:44:25 -07002287 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002288 }
2289
Matt Roper794a9fd2014-06-30 16:44:26 -07002290 if (cursor->position_changed) {
2291 int x = cursor->crtc_x;
2292 int y = cursor->crtc_y;
2293
2294 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002295 "MoveCursor pipe %s, (%d, %d)\n",
2296 kmstest_pipe_name(pipe->pipe),
Matt Roper794a9fd2014-06-30 16:44:26 -07002297 x, y);
2298
2299 ret = drmModeMoveCursor(display->drm_fd, crtc_id, x, y);
2300 CHECK_RETURN(ret, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002301 }
2302
2303 return 0;
2304}
2305
2306/*
2307 * Commit position and fb changes to a primary plane via the legacy interface
2308 * (setmode).
2309 */
2310static int igt_primary_plane_commit_legacy(igt_plane_t *primary,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002311 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002312 bool fail_on_error)
2313{
2314 struct igt_display *display = primary->pipe->display;
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002315 igt_output_t *output = igt_pipe_get_output(pipe);
Matt Roper794a9fd2014-06-30 16:44:26 -07002316 drmModeModeInfo *mode;
2317 uint32_t fb_id, crtc_id;
2318 int ret;
2319
2320 /* Primary planes can't be windowed when using a legacy commit */
2321 igt_assert((primary->crtc_x == 0 && primary->crtc_y == 0));
2322
Damien Lespiau068efd82014-07-08 16:02:05 +01002323 /* nor rotated */
2324 igt_assert(!primary->rotation_changed);
2325
Yi Sunb5333b42014-05-23 08:28:47 +08002326 if (!primary->fb_changed && !primary->position_changed &&
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002327 !primary->size_changed)
Matt Roper794a9fd2014-06-30 16:44:26 -07002328 return 0;
2329
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002330 crtc_id = pipe->crtc_id;
Matt Roper794a9fd2014-06-30 16:44:26 -07002331 fb_id = igt_plane_get_fb_id(primary);
2332 if (fb_id)
2333 mode = igt_output_get_mode(output);
2334 else
2335 mode = NULL;
2336
2337 if (fb_id) {
2338 LOG(display,
Maarten Lankhorst0e29ce32016-06-30 11:32:10 +02002339 "%s: SetCrtc pipe %s, fb %u, src (%d, %d), "
Matt Roper794a9fd2014-06-30 16:44:26 -07002340 "mode %dx%d\n",
2341 igt_output_name(output),
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002342 kmstest_pipe_name(pipe->pipe),
Matt Roper794a9fd2014-06-30 16:44:26 -07002343 fb_id,
Matt Roperdb636a72016-08-03 09:15:41 -07002344 primary->src_x, primary->src_y,
Matt Roper794a9fd2014-06-30 16:44:26 -07002345 mode->hdisplay, mode->vdisplay);
2346
2347 ret = drmModeSetCrtc(display->drm_fd,
2348 crtc_id,
2349 fb_id,
Matt Roperdb636a72016-08-03 09:15:41 -07002350 primary->src_x, primary->src_y,
Matt Roper794a9fd2014-06-30 16:44:26 -07002351 &output->id,
2352 1,
2353 mode);
2354 } else {
2355 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002356 "SetCrtc pipe %s, disabling\n",
2357 kmstest_pipe_name(pipe->pipe));
Matt Roper794a9fd2014-06-30 16:44:26 -07002358
2359 ret = drmModeSetCrtc(display->drm_fd,
2360 crtc_id,
2361 fb_id,
2362 0, 0, /* x, y */
2363 NULL, /* connectors */
2364 0, /* n_connectors */
2365 NULL /* mode */);
2366 }
2367
2368 CHECK_RETURN(ret, fail_on_error);
2369
2370 primary->pipe->enabled = (fb_id != 0);
Matt Roper794a9fd2014-06-30 16:44:26 -07002371
2372 return 0;
2373}
2374
2375
2376/*
2377 * Commit position and fb changes to a plane. The value of @s will determine
2378 * which API is used to do the programming.
2379 */
2380static int igt_plane_commit(igt_plane_t *plane,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002381 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002382 enum igt_commit_style s,
2383 bool fail_on_error)
2384{
Robert Foss36656232017-01-18 12:28:45 -05002385 if (plane->type == DRM_PLANE_TYPE_CURSOR && s == COMMIT_LEGACY) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002386 return igt_cursor_commit_legacy(plane, pipe, fail_on_error);
Robert Foss36656232017-01-18 12:28:45 -05002387 } else if (plane->type == DRM_PLANE_TYPE_PRIMARY && s == COMMIT_LEGACY) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002388 return igt_primary_plane_commit_legacy(plane, pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002389 fail_on_error);
2390 } else {
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002391 return igt_drm_plane_commit(plane, pipe, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002392 }
2393}
2394
2395/*
2396 * Commit all plane changes to an output. Note that if @s is COMMIT_LEGACY,
2397 * enabling/disabling the primary plane will also enable/disable the CRTC.
2398 *
2399 * If @fail_on_error is true, any failure to commit plane state will lead
2400 * to subtest failure in the specific function where the failure occurs.
2401 * Otherwise, the first error code encountered will be returned and no
2402 * further programming will take place, which may result in some changes
2403 * taking effect and others not taking effect.
2404 */
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002405static int igt_pipe_commit(igt_pipe_t *pipe,
2406 enum igt_commit_style s,
2407 bool fail_on_error)
Matt Roper794a9fd2014-06-30 16:44:26 -07002408{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002409 igt_display_t *display = pipe->display;
Matt Roper794a9fd2014-06-30 16:44:26 -07002410 int i;
2411 int ret;
2412 bool need_wait_for_vblank = false;
2413
chandra konduruace42082015-03-30 13:44:32 -07002414 if (pipe->background_changed) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002415 igt_crtc_set_property(pipe, pipe->background_property,
chandra konduruace42082015-03-30 13:44:32 -07002416 pipe->background);
chandra konduruace42082015-03-30 13:44:32 -07002417 }
2418
Lionel Landwerlin17166252016-03-18 17:33:01 +00002419 if (pipe->color_mgmt_changed) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002420 igt_crtc_set_property(pipe, pipe->degamma_property,
Lionel Landwerlin17166252016-03-18 17:33:01 +00002421 pipe->degamma_blob);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002422 igt_crtc_set_property(pipe, pipe->ctm_property,
Lionel Landwerlin17166252016-03-18 17:33:01 +00002423 pipe->ctm_blob);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002424 igt_crtc_set_property(pipe, pipe->gamma_property,
Lionel Landwerlin17166252016-03-18 17:33:01 +00002425 pipe->gamma_blob);
Lionel Landwerlin17166252016-03-18 17:33:01 +00002426 }
2427
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002428 for (i = 0; i < pipe->n_planes; i++) {
2429 igt_plane_t *plane = &pipe->planes[i];
2430
chandra kondurua26f9f92015-03-30 13:52:04 -07002431 if (plane->fb_changed || plane->position_changed || plane->size_changed)
Matt Roper2a3e2122014-06-30 16:44:23 -07002432 need_wait_for_vblank = true;
2433
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002434 ret = igt_plane_commit(plane, pipe, s, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002435 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002436 }
2437
Matt Roper2a3e2122014-06-30 16:44:23 -07002438 /*
2439 * If the crtc is enabled, wait until the next vblank before returning
2440 * if we made changes to any of the planes.
2441 */
Matt Roper794a9fd2014-06-30 16:44:26 -07002442 if (need_wait_for_vblank && pipe->enabled) {
Damien Lespiaufb146aa2014-02-06 21:18:28 +00002443 igt_wait_for_vblank(display->drm_fd, pipe->pipe);
Damien Lespiaufb146aa2014-02-06 21:18:28 +00002444 }
2445
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002446 return 0;
2447}
2448
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002449static void
2450igt_pipe_replace_blob(igt_pipe_t *pipe, uint64_t *blob, void *ptr, size_t length)
2451{
2452 igt_display_t *display = pipe->display;
2453 uint32_t blob_id = 0;
2454
2455 if (*blob != 0)
2456 igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
2457 *blob) == 0);
2458
2459 if (length > 0)
2460 igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
2461 ptr, length, &blob_id) == 0);
2462
2463 *blob = blob_id;
2464}
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302465
2466/*
2467 * Add crtc property changes to the atomic property set
2468 */
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002469static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302470{
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302471 if (pipe_obj->background_changed)
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002472 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_BACKGROUND, pipe_obj->background);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302473
Lionel Landwerlin17166252016-03-18 17:33:01 +00002474 if (pipe_obj->color_mgmt_changed) {
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002475 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_DEGAMMA_LUT, pipe_obj->degamma_blob);
2476 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_CTM, pipe_obj->ctm_blob);
2477 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_GAMMA_LUT, pipe_obj->gamma_blob);
Lionel Landwerlin17166252016-03-18 17:33:01 +00002478 }
2479
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002480 if (pipe_obj->mode_changed) {
2481 igt_output_t *output = igt_pipe_get_output(pipe_obj);
2482
2483 if (!output) {
2484 igt_pipe_replace_blob(pipe_obj, &pipe_obj->mode_blob, NULL, 0);
2485
2486 LOG(pipe_obj->display, "%s: Setting NULL mode\n",
2487 kmstest_pipe_name(pipe_obj->pipe));
2488 } else {
2489 drmModeModeInfo *mode = igt_output_get_mode(output);
2490
2491 igt_pipe_replace_blob(pipe_obj, &pipe_obj->mode_blob, mode, sizeof(*mode));
2492
2493 LOG(pipe_obj->display, "%s: Setting mode %s from %s\n",
2494 kmstest_pipe_name(pipe_obj->pipe),
2495 mode->name, igt_output_name(output));
2496 }
2497
2498 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_MODE_ID, pipe_obj->mode_blob);
2499 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_ACTIVE, !!output);
2500 }
2501
Gustavo Padovan513846b2016-06-20 10:24:08 -04002502 pipe_obj->out_fence_fd = -1;
2503 if (pipe_obj->out_fence_requested)
2504 {
2505 pipe_obj->out_fence_requested = false;
2506 igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_OUT_FENCE_PTR,
2507 (uint64_t)(uintptr_t) &pipe_obj->out_fence_fd);
2508 }
2509
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302510 /*
2511 * TODO: Add all crtc level properties here
2512 */
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302513}
2514
2515/*
2516 * Add connector property changes to the atomic property set
2517 */
2518static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
2519{
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002520
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302521 struct kmstest_connector_config *config = &output->config;
2522
2523 if (config->connector_scaling_mode_changed)
2524 igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_SCALING_MODE, config->connector_scaling_mode);
2525
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002526 if (config->pipe_changed) {
2527 uint32_t crtc_id = 0;
2528
2529 if (output->config.pipe != PIPE_NONE)
2530 crtc_id = output->config.crtc->crtc_id;
2531
2532 igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_CRTC_ID, crtc_id);
2533 }
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302534 /*
2535 * TODO: Add all other connector level properties here
2536 */
2537
2538}
2539
2540/*
2541 * Commit all the changes of all the planes,crtcs, connectors
2542 * atomically using drmModeAtomicCommit()
2543 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002544static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_data)
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302545{
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002546
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002547 int ret = 0, i;
2548 enum pipe pipe;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302549 drmModeAtomicReq *req;
2550 igt_output_t *output;
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002551
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302552 if (display->is_atomic != 1)
2553 return -1;
2554 req = drmModeAtomicAlloc();
2555 drmModeAtomicSetCursor(req, 0);
2556
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002557 for_each_pipe(display, pipe) {
2558 igt_pipe_t *pipe_obj = &display->pipes[pipe];
Maarten Lankhorst4a185972016-06-28 14:28:20 +02002559 igt_plane_t *plane;
2560
2561 /*
2562 * Add CRTC Properties to the property set
2563 */
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002564 igt_atomic_prepare_crtc_commit(pipe_obj, req);
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002565
2566 for_each_plane_on_pipe(display, pipe, plane) {
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002567 igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
Maarten Lankhorst0404de42016-06-29 15:56:28 +02002568 }
2569
Maarten Lankhorst4a185972016-06-28 14:28:20 +02002570 }
2571
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002572 for (i = 0; i < display->n_outputs; i++) {
2573 output = &display->outputs[i];
2574
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002575 if (!output->config.connector)
2576 continue;
2577
2578 LOG(display, "%s: preparing atomic, pipe: %s\n",
2579 igt_output_name(output),
2580 kmstest_pipe_name(output->config.pipe));
2581
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002582 igt_atomic_prepare_connector_commit(output, req);
2583 }
2584
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002585 ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data);
Robert Foss187ccf02017-01-31 11:43:35 -05002586 if (!ret) {
2587
2588 for_each_pipe(display, pipe) {
2589 igt_pipe_t *pipe_obj = &display->pipes[pipe];
Gustavo Padovanf8aa5962016-11-07 10:32:49 +00002590 igt_plane_t *plane;
2591
2592 /* reset fence_fd to prevent it from being set for the next commit */
2593 for_each_plane_on_pipe(display, pipe, plane) {
2594 igt_plane_set_fence_fd(plane, -1);
2595 }
Robert Foss187ccf02017-01-31 11:43:35 -05002596
2597 if (pipe_obj->out_fence_fd == -1)
2598 continue;
2599
2600 igt_assert(pipe_obj->out_fence_fd >= 0);
2601 ret = sync_fence_wait(pipe_obj->out_fence_fd, 1000);
2602 igt_assert(ret == 0);
2603 close(pipe_obj->out_fence_fd);
2604 pipe_obj->out_fence_fd = -1;
2605 }
2606 }
2607
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302608 drmModeAtomicFree(req);
2609 return ret;
2610
2611}
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002612
2613static void
2614display_commit_changed(igt_display_t *display, enum igt_commit_style s)
Matt Roper82bc03f2014-06-30 16:44:25 -07002615{
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002616 int i;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002617 enum pipe pipe;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002618
2619 for_each_pipe(display, pipe) {
2620 igt_pipe_t *pipe_obj = &display->pipes[pipe];
2621 igt_plane_t *plane;
2622
2623 pipe_obj->color_mgmt_changed = false;
2624 pipe_obj->background_changed = false;
2625
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002626 if (s != COMMIT_UNIVERSAL)
2627 pipe_obj->mode_changed = false;
2628
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002629 for_each_plane_on_pipe(display, pipe, plane) {
2630 plane->fb_changed = false;
2631 plane->position_changed = false;
2632 plane->size_changed = false;
2633
Robert Foss36656232017-01-18 12:28:45 -05002634 if (s != COMMIT_LEGACY ||
2635 !(plane->type == DRM_PLANE_TYPE_PRIMARY ||
2636 plane->type == DRM_PLANE_TYPE_CURSOR))
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002637 plane->rotation_changed = false;
2638 }
2639 }
2640
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002641 for (i = 0; i < display->n_outputs; i++) {
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002642 igt_output_t *output = &display->outputs[i];
2643
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002644 if (s != COMMIT_UNIVERSAL)
2645 output->config.pipe_changed = false;
2646
2647 if (s == COMMIT_ATOMIC)
2648 output->config.connector_scaling_mode_changed = false;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002649 }
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002650}
2651
2652/*
2653 * Commit all plane changes across all outputs of the display.
2654 *
2655 * If @fail_on_error is true, any failure to commit plane state will lead
2656 * to subtest failure in the specific function where the failure occurs.
2657 * Otherwise, the first error code encountered will be returned and no
2658 * further programming will take place, which may result in some changes
2659 * taking effect and others not taking effect.
2660 */
2661static int do_display_commit(igt_display_t *display,
2662 enum igt_commit_style s,
2663 bool fail_on_error)
2664{
2665 int ret;
2666 enum pipe pipe;
2667 LOG_INDENT(display, "commit");
2668
2669 igt_display_refresh(display);
2670
2671 if (s == COMMIT_ATOMIC) {
2672 ret = igt_atomic_commit(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
2673
2674 CHECK_RETURN(ret, fail_on_error);
2675 } else {
2676 int valid_outs = 0;
2677
2678 for_each_pipe(display, pipe) {
2679 igt_pipe_t *pipe_obj = &display->pipes[pipe];
2680 igt_output_t *output = igt_pipe_get_output(pipe_obj);
2681
Maarten Lankhorstba237f92017-01-10 10:50:50 +01002682 if (output)
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002683 valid_outs++;
2684
2685 ret = igt_pipe_commit(pipe_obj, s, fail_on_error);
2686 CHECK_RETURN(ret, fail_on_error);
2687 }
2688
2689 CHECK_RETURN(ret, fail_on_error);
2690
2691 if (valid_outs == 0) {
2692 LOG_UNINDENT(display);
2693
2694 return -1;
2695 }
2696 }
2697
2698 LOG_UNINDENT(display);
2699
2700 if (ret)
2701 return ret;
2702
2703 display_commit_changed(display, s);
Feceoru, Gabriel26bec972016-02-26 13:21:15 +02002704
Daniel Vetterc49542a2014-09-05 08:51:27 +02002705 igt_debug_wait_for_keypress("modeset");
Matt Roper82bc03f2014-06-30 16:44:25 -07002706
2707 return 0;
2708}
2709
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02002710/**
2711 * igt_display_try_commit_atomic:
2712 * @display: #igt_display_t to commit.
2713 * @flags: Flags passed to drmModeAtomicCommit.
2714 * @user_data: User defined pointer passed to drmModeAtomicCommit.
2715 *
2716 * This function is similar to #igt_display_try_commit2, but is
2717 * used when you want to pass different flags to the actual commit.
2718 *
2719 * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
2720 * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
2721 * or DRM_MODE_ATOMIC_TEST_ONLY.
2722 *
2723 * @user_data is returned in the event if you pass
2724 * DRM_MODE_PAGE_FLIP_EVENT to @flags.
2725 *
2726 * This function will return an error if commit fails, instead of
2727 * aborting the test.
2728 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002729int igt_display_try_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
2730{
2731 int ret;
2732
2733 LOG_INDENT(display, "commit");
2734
2735 igt_display_refresh(display);
2736
2737 ret = igt_atomic_commit(display, flags, user_data);
2738
2739 LOG_UNINDENT(display);
2740
2741 if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))
2742 return ret;
2743
2744 display_commit_changed(display, COMMIT_ATOMIC);
2745
2746 igt_debug_wait_for_keypress("modeset");
2747
2748 return 0;
2749}
2750
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02002751/**
2752 * igt_display_commit_atomic:
2753 * @display: #igt_display_t to commit.
2754 * @flags: Flags passed to drmModeAtomicCommit.
2755 * @user_data: User defined pointer passed to drmModeAtomicCommit.
2756 *
2757 * This function is similar to #igt_display_commit2, but is
2758 * used when you want to pass different flags to the actual commit.
2759 *
2760 * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
2761 * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
2762 * or DRM_MODE_ATOMIC_TEST_ONLY.
2763 *
2764 * @user_data is returned in the event if you pass
2765 * DRM_MODE_PAGE_FLIP_EVENT to @flags.
2766 *
2767 * This function will abort the test if commit fails.
2768 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002769void igt_display_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
2770{
2771 int ret = igt_display_try_commit_atomic(display, flags, user_data);
2772
2773 igt_assert_eq(ret, 0);
2774}
2775
Matt Roper1c255472014-06-30 16:44:24 -07002776/**
2777 * igt_display_commit2:
2778 * @display: DRM device handle
2779 * @s: Commit style
2780 *
2781 * Commits framebuffer and positioning changes to all planes of each display
2782 * pipe, using a specific API to perform the programming. This function should
2783 * be used to exercise a specific driver programming API; igt_display_commit
2784 * should be used instead if the API used is unimportant to the test being run.
2785 *
Matt Roper82bc03f2014-06-30 16:44:25 -07002786 * This function should only be used to commit changes that are expected to
2787 * succeed, since any failure during the commit process will cause the IGT
2788 * subtest to fail. To commit changes that are expected to fail, use
2789 * @igt_try_display_commit2 instead.
2790 *
Matt Roper1c255472014-06-30 16:44:24 -07002791 * Returns: 0 upon success. This function will never return upon failure
2792 * since igt_fail() at lower levels will longjmp out of it.
2793 */
2794int igt_display_commit2(igt_display_t *display,
2795 enum igt_commit_style s)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002796{
Matt Roper794a9fd2014-06-30 16:44:26 -07002797 do_display_commit(display, s, true);
2798
2799 return 0;
Matt Roper82bc03f2014-06-30 16:44:25 -07002800}
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002801
Matt Roper82bc03f2014-06-30 16:44:25 -07002802/**
2803 * igt_display_try_commit2:
2804 * @display: DRM device handle
2805 * @s: Commit style
2806 *
2807 * Attempts to commit framebuffer and positioning changes to all planes of each
2808 * display pipe. This function should be used to commit changes that are
2809 * expected to fail, so that the error code can be checked for correctness.
2810 * For changes that are expected to succeed, use @igt_display_commit instead.
2811 *
2812 * Note that in non-atomic commit styles, no display programming will be
2813 * performed after the first failure is encountered, so only some of the
2814 * operations requested by a test may have been completed. Tests that catch
2815 * errors returned by this function should take care to restore the display to
2816 * a sane state after a failure is detected.
2817 *
2818 * Returns: 0 upon success, otherwise the error code of the first error
2819 * encountered.
2820 */
2821int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s)
2822{
Matt Roper794a9fd2014-06-30 16:44:26 -07002823 return do_display_commit(display, s, false);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002824}
2825
Matt Roper1c255472014-06-30 16:44:24 -07002826/**
2827 * igt_display_commit:
2828 * @display: DRM device handle
Matt Roper1c255472014-06-30 16:44:24 -07002829 *
2830 * Commits framebuffer and positioning changes to all planes of each display
2831 * pipe.
2832 *
2833 * Returns: 0 upon success. This function will never return upon failure
2834 * since igt_fail() at lower levels will longjmp out of it.
2835 */
2836int igt_display_commit(igt_display_t *display)
2837{
2838 return igt_display_commit2(display, COMMIT_LEGACY);
2839}
2840
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002841const char *igt_output_name(igt_output_t *output)
2842{
2843 return output->name;
2844}
2845
2846drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
2847{
2848 return &output->config.default_mode;
2849}
2850
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03002851/**
2852 * igt_output_override_mode:
Thomas Woodd01ebbd2015-06-29 16:47:14 +01002853 * @output: Output of which the mode will be overridden
Maarten Lankhorst11eeb472016-07-05 15:09:56 +02002854 * @mode: New mode, or NULL to disable override.
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03002855 *
2856 * Overrides the output's mode with @mode, so that it is used instead of the
2857 * mode obtained with get connectors. Note that the mode is used without
Thomas Woodd01ebbd2015-06-29 16:47:14 +01002858 * checking if the output supports it, so this might lead to unexpected results.
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03002859 */
2860void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode)
2861{
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002862 igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
2863
Maarten Lankhorst11eeb472016-07-05 15:09:56 +02002864 if (mode)
2865 output->override_mode = *mode;
2866 else /* restore default_mode, may have been overwritten in igt_output_refresh */
2867 kmstest_get_connector_default_mode(output->display->drm_fd,
2868 output->config.connector,
2869 &output->config.default_mode);
2870
2871 output->use_override_mode = !!mode;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002872
2873 if (pipe)
2874 pipe->mode_changed = true;
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03002875}
2876
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002877void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
2878{
2879 igt_display_t *display = output->display;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002880 igt_pipe_t *old_pipe;
2881
Maarten Lankhorstba237f92017-01-10 10:50:50 +01002882 igt_assert(output->name);
Chris Wilson1b17be52016-08-23 11:27:45 +01002883
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002884 if (output->pending_crtc_idx_mask) {
2885 old_pipe = igt_output_get_driving_pipe(output);
2886
2887 old_pipe->mode_changed = true;
2888 }
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002889
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002890 if (pipe == PIPE_NONE) {
Damien Lespiau09faa452014-02-06 15:45:42 +00002891 LOG(display, "%s: set_pipe(any)\n", igt_output_name(output));
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002892 output->pending_crtc_idx_mask = 0;
Damien Lespiau09faa452014-02-06 15:45:42 +00002893 } else {
Daniel Vetterdd8fba42014-08-12 11:00:37 +02002894 LOG(display, "%s: set_pipe(%s)\n", igt_output_name(output),
2895 kmstest_pipe_name(pipe));
Damien Lespiau09faa452014-02-06 15:45:42 +00002896 output->pending_crtc_idx_mask = 1 << pipe;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002897
2898 display->pipes[pipe].mode_changed = true;
Damien Lespiau09faa452014-02-06 15:45:42 +00002899 }
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02002900
Maarten Lankhorst35afbb02017-01-24 16:04:46 +01002901 output->config.pipe_changed = true;
Maarten Lankhorstd8518f32016-10-05 13:39:29 +02002902
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002903 igt_output_refresh(output);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002904}
2905
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002906void igt_output_set_scaling_mode(igt_output_t *output, uint64_t scaling_mode)
2907{
2908 output->config.connector_scaling_mode_changed = true;
2909
2910 output->config.connector_scaling_mode = scaling_mode;
2911
2912 igt_require(output->config.atomic_props_connector[IGT_CONNECTOR_SCALING_MODE]);
2913}
2914
Robert Foss36656232017-01-18 12:28:45 -05002915igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002916{
2917 igt_pipe_t *pipe;
2918
2919 pipe = igt_output_get_driving_pipe(output);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002920 igt_assert(pipe);
2921
Robert Foss36656232017-01-18 12:28:45 -05002922 return igt_pipe_get_plane(pipe, plane_idx);
2923}
2924
2925igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type)
2926{
2927 igt_pipe_t *pipe;
2928
2929 pipe = igt_output_get_driving_pipe(output);
2930 igt_assert(pipe);
2931
2932 return igt_pipe_get_plane_type(pipe, plane_type);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002933}
2934
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002935void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002936{
2937 igt_pipe_t *pipe = plane->pipe;
2938 igt_display_t *display = pipe->display;
2939
Daniel Vetterdd8fba42014-08-12 11:00:37 +02002940 LOG(display, "%s.%d: plane_set_fb(%d)\n", kmstest_pipe_name(pipe->pipe),
Damien Lespiauda0f1cf2014-02-06 21:06:59 +00002941 plane->index, fb ? fb->fb_id : 0);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002942
2943 plane->fb = fb;
Ville Syrjälä7b767542014-09-12 20:18:04 +03002944 /* hack to keep tests working that don't call igt_plane_set_size() */
2945 if (fb) {
Tvrtko Ursulin980ccf12015-05-12 11:06:37 +01002946 /* set default plane size as fb size */
chandra kondurua26f9f92015-03-30 13:52:04 -07002947 plane->crtc_w = fb->width;
2948 plane->crtc_h = fb->height;
2949
2950 /* set default src pos/size as fb size */
Lionel Landwerlincd8da3f2016-04-05 14:13:53 +01002951 plane->src_x = 0;
2952 plane->src_y = 0;
2953 plane->src_w = fb->width;
2954 plane->src_h = fb->height;
Tvrtko Ursulinc3bd6082015-05-12 11:06:36 +01002955 } else {
Maarten Lankhorst826150f2016-07-05 14:52:20 +02002956 plane->src_x = 0;
2957 plane->src_y = 0;
2958 plane->src_w = 0;
2959 plane->src_h = 0;
2960
Tvrtko Ursulinc3bd6082015-05-12 11:06:36 +01002961 plane->crtc_w = 0;
2962 plane->crtc_h = 0;
chandra kondurua26f9f92015-03-30 13:52:04 -07002963 }
2964
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002965 plane->fb_changed = true;
chandra kondurua26f9f92015-03-30 13:52:04 -07002966 plane->size_changed = true;
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002967}
2968
Robert Foss221848d2016-06-20 10:24:08 -04002969/**
2970 * igt_plane_set_fence_fd:
2971 * @plane: plane
2972 * @fence_fd: fence fd, disable fence_fd by setting it to -1
2973 *
2974 * This function sets a fence fd to enable a commit to wait for some event to
2975 * occur before completing.
2976 */
2977void igt_plane_set_fence_fd(igt_plane_t *plane, int fence_fd)
2978{
2979 close(plane->fence_fd);
2980
2981 if (fcntl(fence_fd, F_GETFD) != -1)
2982 plane->fence_fd = dup(fence_fd);
2983 else
2984 plane->fence_fd = -1;
2985}
2986
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002987void igt_plane_set_position(igt_plane_t *plane, int x, int y)
2988{
2989 igt_pipe_t *pipe = plane->pipe;
2990 igt_display_t *display = pipe->display;
2991
Daniel Vetterdd8fba42014-08-12 11:00:37 +02002992 LOG(display, "%s.%d: plane_set_position(%d,%d)\n",
2993 kmstest_pipe_name(pipe->pipe), plane->index, x, y);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002994
2995 plane->crtc_x = x;
2996 plane->crtc_y = y;
2997
2998 plane->position_changed = true;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002999}
Daniel Vetter64401f52014-03-26 10:19:42 +01003000
chandra kondurua26f9f92015-03-30 13:52:04 -07003001/**
3002 * igt_plane_set_size:
3003 * @plane: plane pointer for which size to be set
3004 * @w: width
3005 * @h: height
3006 *
3007 * This function sets width and height for requested plane.
Thomas Woodd01ebbd2015-06-29 16:47:14 +01003008 * New size will be committed at plane commit time via
chandra kondurua26f9f92015-03-30 13:52:04 -07003009 * drmModeSetPlane().
3010 */
Ville Syrjälä7b767542014-09-12 20:18:04 +03003011void igt_plane_set_size(igt_plane_t *plane, int w, int h)
3012{
3013 igt_pipe_t *pipe = plane->pipe;
3014 igt_display_t *display = pipe->display;
3015
chandra kondurua26f9f92015-03-30 13:52:04 -07003016 LOG(display, "%s.%d: plane_set_size (%dx%d)\n",
Ville Syrjälä7b767542014-09-12 20:18:04 +03003017 kmstest_pipe_name(pipe->pipe), plane->index, w, h);
3018
3019 plane->crtc_w = w;
3020 plane->crtc_h = h;
3021
chandra kondurua26f9f92015-03-30 13:52:04 -07003022 plane->size_changed = true;
3023}
3024
3025/**
3026 * igt_fb_set_position:
3027 * @fb: framebuffer pointer
Thomas Wood6141aa22015-05-14 16:00:25 +01003028 * @plane: plane
chandra kondurua26f9f92015-03-30 13:52:04 -07003029 * @x: X position
3030 * @y: Y position
3031 *
3032 * This function sets position for requested framebuffer as src to plane.
Thomas Wood6141aa22015-05-14 16:00:25 +01003033 * New position will be committed at plane commit time via drmModeSetPlane().
chandra kondurua26f9f92015-03-30 13:52:04 -07003034 */
3035void igt_fb_set_position(struct igt_fb *fb, igt_plane_t *plane,
3036 uint32_t x, uint32_t y)
3037{
3038 igt_pipe_t *pipe = plane->pipe;
3039 igt_display_t *display = pipe->display;
3040
3041 LOG(display, "%s.%d: fb_set_position(%d,%d)\n",
3042 kmstest_pipe_name(pipe->pipe), plane->index, x, y);
3043
Lionel Landwerlincd8da3f2016-04-05 14:13:53 +01003044 plane->src_x = x;
3045 plane->src_y = y;
chandra kondurua26f9f92015-03-30 13:52:04 -07003046
3047 plane->fb_changed = true;
3048}
3049
3050/**
Thomas Wood6141aa22015-05-14 16:00:25 +01003051 * igt_fb_set_size:
chandra kondurua26f9f92015-03-30 13:52:04 -07003052 * @fb: framebuffer pointer
Thomas Wood6141aa22015-05-14 16:00:25 +01003053 * @plane: plane
chandra kondurua26f9f92015-03-30 13:52:04 -07003054 * @w: width
3055 * @h: height
3056 *
3057 * This function sets fetch rect size from requested framebuffer as src
Thomas Wood6141aa22015-05-14 16:00:25 +01003058 * to plane. New size will be committed at plane commit time via
chandra kondurua26f9f92015-03-30 13:52:04 -07003059 * drmModeSetPlane().
3060 */
3061void igt_fb_set_size(struct igt_fb *fb, igt_plane_t *plane,
3062 uint32_t w, uint32_t h)
3063{
3064 igt_pipe_t *pipe = plane->pipe;
3065 igt_display_t *display = pipe->display;
3066
Ville Syrjälä0c028732016-02-12 21:15:07 +02003067 LOG(display, "%s.%d: fb_set_size(%dx%d)\n",
chandra kondurua26f9f92015-03-30 13:52:04 -07003068 kmstest_pipe_name(pipe->pipe), plane->index, w, h);
3069
Lionel Landwerlincd8da3f2016-04-05 14:13:53 +01003070 plane->src_w = w;
3071 plane->src_h = h;
chandra kondurua26f9f92015-03-30 13:52:04 -07003072
Ville Syrjälä7b767542014-09-12 20:18:04 +03003073 plane->fb_changed = true;
3074}
3075
Damien Lespiau068efd82014-07-08 16:02:05 +01003076static const char *rotation_name(igt_rotation_t rotation)
3077{
3078 switch (rotation) {
3079 case IGT_ROTATION_0:
3080 return "0°";
3081 case IGT_ROTATION_90:
3082 return "90°";
3083 case IGT_ROTATION_180:
3084 return "180°";
3085 case IGT_ROTATION_270:
3086 return "270°";
3087 default:
3088 igt_assert(0);
3089 }
3090}
3091
3092void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation)
3093{
3094 igt_pipe_t *pipe = plane->pipe;
3095 igt_display_t *display = pipe->display;
3096
Daniel Vetterdd8fba42014-08-12 11:00:37 +02003097 LOG(display, "%s.%d: plane_set_rotation(%s)\n",
3098 kmstest_pipe_name(pipe->pipe),
Damien Lespiau068efd82014-07-08 16:02:05 +01003099 plane->index, rotation_name(rotation));
3100
3101 plane->rotation = rotation;
3102
3103 plane->rotation_changed = true;
3104}
3105
Gustavo Padovan513846b2016-06-20 10:24:08 -04003106/**
3107 * igt_pipe_request_out_fence:
3108 * @pipe: pipe which out fence will be requested for
3109 *
3110 * Marks this pipe for requesting an out fence at the next atomic commit
3111 * will contain the fd number of the out fence created by KMS.
3112 */
3113void igt_pipe_request_out_fence(igt_pipe_t *pipe)
3114{
3115 pipe->out_fence_requested = true;
3116}
3117
Lionel Landwerlin17166252016-03-18 17:33:01 +00003118void
3119igt_pipe_set_degamma_lut(igt_pipe_t *pipe, void *ptr, size_t length)
3120{
3121 igt_pipe_replace_blob(pipe, &pipe->degamma_blob, ptr, length);
3122 pipe->color_mgmt_changed = 1;
3123}
3124
3125void
3126igt_pipe_set_ctm_matrix(igt_pipe_t *pipe, void *ptr, size_t length)
3127{
3128 igt_pipe_replace_blob(pipe, &pipe->ctm_blob, ptr, length);
3129 pipe->color_mgmt_changed = 1;
3130}
3131
3132void
3133igt_pipe_set_gamma_lut(igt_pipe_t *pipe, void *ptr, size_t length)
3134{
3135 igt_pipe_replace_blob(pipe, &pipe->gamma_blob, ptr, length);
3136 pipe->color_mgmt_changed = 1;
3137}
3138
chandra konduruace42082015-03-30 13:44:32 -07003139/**
3140 * igt_crtc_set_background:
3141 * @pipe: pipe pointer to which background color to be set
3142 * @background: background color value in BGR 16bpc
3143 *
3144 * Sets background color for requested pipe. Color value provided here
3145 * will be actually submitted at output commit time via "background_color"
3146 * property.
3147 * For example to get red as background, set background = 0x00000000FFFF.
3148 */
3149void igt_crtc_set_background(igt_pipe_t *pipe, uint64_t background)
3150{
3151 igt_display_t *display = pipe->display;
3152
Ville Syrjälä1ecd91a2015-12-13 00:04:43 +02003153 LOG(display, "%s.%d: crtc_set_background(%"PRIx64")\n",
chandra konduruace42082015-03-30 13:44:32 -07003154 kmstest_pipe_name(pipe->pipe),
3155 pipe->pipe, background);
3156
3157 pipe->background = background;
3158
3159 pipe->background_changed = true;
3160}
3161
Chris Wilson2c64f112017-03-13 15:58:26 +00003162void igt_wait_for_vblank_count(int drm_fd, enum pipe pipe, int count)
Daniel Vetter64401f52014-03-26 10:19:42 +01003163{
3164 drmVBlank wait_vbl;
Robert Foss8a4e62b2016-05-18 20:07:08 -04003165 uint32_t pipe_id_flag;
Daniel Vetter64401f52014-03-26 10:19:42 +01003166
3167 memset(&wait_vbl, 0, sizeof(wait_vbl));
Robert Foss8a4e62b2016-05-18 20:07:08 -04003168 pipe_id_flag = kmstest_get_vbl_flag(pipe);
Daniel Vetter64401f52014-03-26 10:19:42 +01003169
Robert Foss8a4e62b2016-05-18 20:07:08 -04003170 wait_vbl.request.type = DRM_VBLANK_RELATIVE;
3171 wait_vbl.request.type |= pipe_id_flag;
Chris Wilson2c64f112017-03-13 15:58:26 +00003172 wait_vbl.request.sequence = count;
Daniel Vetter64401f52014-03-26 10:19:42 +01003173
3174 igt_assert(drmWaitVBlank(drm_fd, &wait_vbl) == 0);
3175}
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003176
Chris Wilson2c64f112017-03-13 15:58:26 +00003177void igt_wait_for_vblank(int drm_fd, enum pipe pipe)
3178{
3179 igt_wait_for_vblank_count(drm_fd, pipe, 1);
3180}
3181
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003182/**
3183 * igt_enable_connectors:
3184 *
3185 * Force connectors to be enabled where this is known to work well. Use
3186 * #igt_reset_connectors to revert the changes.
3187 *
3188 * An exit handler is installed to ensure connectors are reset when the test
3189 * exits.
3190 */
3191void igt_enable_connectors(void)
3192{
3193 drmModeRes *res;
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003194 int drm_fd;
3195
Tomeu Vizosof4718c22016-02-24 10:47:09 +01003196 drm_fd = drm_open_driver(DRIVER_ANY);
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003197
3198 res = drmModeGetResources(drm_fd);
Chris Wilson53b52f42016-09-14 22:14:22 +01003199 igt_assert(res != NULL);
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003200
3201 for (int i = 0; i < res->count_connectors; i++) {
Chris Wilson53b52f42016-09-14 22:14:22 +01003202 drmModeConnector *c;
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003203
Chris Wilson53b52f42016-09-14 22:14:22 +01003204 /* Do a probe. This may be the first action after booting */
3205 c = drmModeGetConnector(drm_fd, res->connectors[i]);
Maarten Lankhorst3d7a27e2017-02-08 15:47:45 +01003206 if (!c) {
3207 igt_warn("Could not read connector %u: %m\n", res->connectors[i]);
3208 continue;
3209 }
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003210
3211 /* don't attempt to force connectors that are already connected
3212 */
3213 if (c->connection == DRM_MODE_CONNECTED)
3214 continue;
3215
3216 /* just enable VGA for now */
Thomas Woodbb484292014-07-28 16:01:27 +01003217 if (c->connector_type == DRM_MODE_CONNECTOR_VGA) {
3218 if (!kmstest_force_connector(drm_fd, c, FORCE_CONNECTOR_ON))
3219 igt_info("Unable to force state on %s-%d\n",
3220 kmstest_connector_type_str(c->connector_type),
3221 c->connector_type_id);
3222 }
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003223
3224 drmModeFreeConnector(c);
3225 }
Chris Wilson53b52f42016-09-14 22:14:22 +01003226
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003227 close(drm_fd);
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003228}
3229
3230/**
3231 * igt_reset_connectors:
3232 *
3233 * Remove any forced state from the connectors.
3234 */
3235void igt_reset_connectors(void)
3236{
Thomas Woodf675f672014-09-04 11:35:01 +01003237 /* reset the connectors stored in forced_connectors, avoiding any
3238 * functions that are not safe to call in signal handlers */
Chris Wilson0e11bef2016-05-26 15:06:30 +01003239 for (int i = 0; forced_connectors[i]; i++)
3240 igt_sysfs_set(forced_connectors_device[i],
3241 forced_connectors[i],
3242 "detect");
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003243}
Marius Vlad7ead45c2016-07-04 16:52:46 +03003244
Lyude6adb7b32016-11-17 10:06:09 -05003245#ifdef HAVE_UDEV
3246
3247/**
3248 * igt_watch_hotplug:
3249 *
3250 * Begin monitoring udev for sysfs hotplug events.
3251 *
3252 * Returns: a udev monitor for detecting hotplugs on
3253 */
3254struct udev_monitor *igt_watch_hotplug(void)
3255{
3256 struct udev *udev;
3257 struct udev_monitor *mon;
3258 int ret, flags, fd;
3259
3260 udev = udev_new();
3261 igt_assert(udev != NULL);
3262
3263 mon = udev_monitor_new_from_netlink(udev, "udev");
3264 igt_assert(mon != NULL);
3265
3266 ret = udev_monitor_filter_add_match_subsystem_devtype(mon,
3267 "drm",
3268 "drm_minor");
3269 igt_assert_eq(ret, 0);
3270 ret = udev_monitor_filter_update(mon);
3271 igt_assert_eq(ret, 0);
3272 ret = udev_monitor_enable_receiving(mon);
3273 igt_assert_eq(ret, 0);
3274
3275 /* Set the fd for udev as non blocking */
3276 fd = udev_monitor_get_fd(mon);
3277 flags = fcntl(fd, F_GETFL, 0);
3278 igt_assert(flags);
3279
3280 flags |= O_NONBLOCK;
3281 igt_assert_neq(fcntl(fd, F_SETFL, flags), -1);
3282
3283 return mon;
3284}
3285
3286/**
3287 * igt_hotplug_detected:
3288 * @mon: A udev monitor initialized with #igt_watch_hotplug
3289 * @timeout_secs: How long to wait for a hotplug event to occur.
3290 *
3291 * Assert that a hotplug event was received since we last checked the monitor.
3292 *
3293 * Returns: true if a sysfs hotplug event was received, false if we timed out
3294 */
3295bool igt_hotplug_detected(struct udev_monitor *mon, int timeout_secs)
3296{
3297 struct udev_device *dev;
3298 const char *hotplug_val;
3299 struct pollfd fd = {
3300 .fd = udev_monitor_get_fd(mon),
3301 .events = POLLIN
3302 };
3303 bool hotplug_received = false;
3304
3305 /* Go through all of the events pending on the udev monitor. Once we
3306 * receive a hotplug, we continue going through the rest of the events
3307 * so that redundant hotplug events don't change the results of future
3308 * checks
3309 */
3310 while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) {
3311 dev = udev_monitor_receive_device(mon);
3312
3313 hotplug_val = udev_device_get_property_value(dev, "HOTPLUG");
3314 if (hotplug_val && atoi(hotplug_val) == 1)
3315 hotplug_received = true;
3316
3317 udev_device_unref(dev);
3318 }
3319
3320 return hotplug_received;
3321}
3322
3323/**
3324 * igt_flush_hotplugs:
3325 * @mon: A udev monitor initialized with #igt_watch_hotplug
3326 *
3327 * Get rid of any pending hotplug events
3328 */
3329void igt_flush_hotplugs(struct udev_monitor *mon)
3330{
3331 struct udev_device *dev;
3332
3333 while ((dev = udev_monitor_receive_device(mon)))
3334 udev_device_unref(dev);
3335}
3336
3337/**
3338 * igt_cleanup_hotplug:
3339 *
3340 * Cleanup the resources allocated by #igt_watch_hotplug
3341 */
3342void igt_cleanup_hotplug(struct udev_monitor *mon)
3343{
3344 struct udev *udev = udev_monitor_get_udev(mon);
3345
3346 udev_monitor_unref(mon);
3347 mon = NULL;
3348 udev_unref(udev);
3349}
3350#endif
3351
Marius Vlad7ead45c2016-07-04 16:52:46 +03003352/**
3353 * kmstest_get_vbl_flag:
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02003354 * @pipe_id: Pipe to convert to flag representation.
Marius Vlad7ead45c2016-07-04 16:52:46 +03003355 *
3356 * Convert a pipe id into the flag representation
3357 * expected in DRM while processing DRM_IOCTL_WAIT_VBLANK.
3358 */
3359uint32_t kmstest_get_vbl_flag(uint32_t pipe_id)
3360{
3361 if (pipe_id == 0)
3362 return 0;
3363 else if (pipe_id == 1)
3364 return _DRM_VBLANK_SECONDARY;
3365 else {
3366 uint32_t pipe_flag = pipe_id << 1;
3367 igt_assert(!(pipe_flag & ~DRM_VBLANK_HIGH_CRTC_MASK));
3368 return pipe_flag;
3369 }
3370}