blob: 761bb1937b16f1a5b17fc4ae8e4a4c6d0c36b65a [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"
Mike Frysinger030977e2018-01-10 17:12:15 -050029#include <inttypes.h>
Daniel Vetter254f19b2014-03-22 21:29:01 +010030#include <unistd.h>
Oscar Mateo37f26d12013-11-12 11:50:38 +000031#include <stdio.h>
Damien Lespiau3670d6d2014-01-27 16:25:43 +000032#include <stdarg.h>
Oscar Mateo37f26d12013-11-12 11:50:38 +000033#include <fcntl.h>
34#include <sys/stat.h>
35#include <string.h>
Daniel Vetter254f19b2014-03-22 21:29:01 +010036#include <stdlib.h>
Alan Coopersmithcf93bc82014-12-23 19:07:09 -080037#ifdef HAVE_LINUX_KD_H
Oscar Mateo37f26d12013-11-12 11:50:38 +000038#include <linux/kd.h>
Alan Coopersmithcf93bc82014-12-23 19:07:09 -080039#elif HAVE_SYS_KD_H
40#include <sys/kd.h>
41#endif
Antonio Argenzianod75e6762018-02-23 15:14:40 -080042
Lyude6adb7b32016-11-17 10:06:09 -050043#include <libudev.h>
Petri Latvala19c6c042018-01-09 12:11:24 +020044#include <poll.h>
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 *
Arkadiusz Hilereccae132018-05-15 14:07:50 +030077 * Note that this library's header pulls in the [i-g-t framebuffer](igt-gpu-tools-i-g-t-framebuffer.html)
Maarten Lankhorst9ed1af62016-07-27 14:12:40 +020078 * 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
Ville Syrjälä837fea22018-03-05 22:12:58 +0200161const char * const igt_plane_prop_names[IGT_NUM_PLANE_PROPS] = {
Ville Syrjäläc30e3312018-03-05 22:08:21 +0200162 [IGT_PLANE_SRC_X] = "SRC_X",
163 [IGT_PLANE_SRC_Y] = "SRC_Y",
164 [IGT_PLANE_SRC_W] = "SRC_W",
165 [IGT_PLANE_SRC_H] = "SRC_H",
166 [IGT_PLANE_CRTC_X] = "CRTC_X",
167 [IGT_PLANE_CRTC_Y] = "CRTC_Y",
168 [IGT_PLANE_CRTC_W] = "CRTC_W",
169 [IGT_PLANE_CRTC_H] = "CRTC_H",
170 [IGT_PLANE_FB_ID] = "FB_ID",
171 [IGT_PLANE_CRTC_ID] = "CRTC_ID",
172 [IGT_PLANE_IN_FENCE_FD] = "IN_FENCE_FD",
173 [IGT_PLANE_TYPE] = "type",
174 [IGT_PLANE_ROTATION] = "rotation",
175 [IGT_PLANE_IN_FORMATS] = "IN_FORMATS",
Ville Syrjäläa9a683e2018-03-06 20:01:44 +0200176 [IGT_PLANE_COLOR_ENCODING] = "COLOR_ENCODING",
177 [IGT_PLANE_COLOR_RANGE] = "COLOR_RANGE",
Maarten Lankhorstd0975642018-10-01 17:48:12 +0200178 [IGT_PLANE_PIXEL_BLEND_MODE] = "pixel blend mode",
179 [IGT_PLANE_ALPHA] = "alpha",
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530180};
181
Ville Syrjälä837fea22018-03-05 22:12:58 +0200182const char * const igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = {
Ville Syrjäläc30e3312018-03-05 22:08:21 +0200183 [IGT_CRTC_BACKGROUND] = "background_color",
184 [IGT_CRTC_CTM] = "CTM",
185 [IGT_CRTC_GAMMA_LUT] = "GAMMA_LUT",
186 [IGT_CRTC_GAMMA_LUT_SIZE] = "GAMMA_LUT_SIZE",
187 [IGT_CRTC_DEGAMMA_LUT] = "DEGAMMA_LUT",
188 [IGT_CRTC_DEGAMMA_LUT_SIZE] = "DEGAMMA_LUT_SIZE",
189 [IGT_CRTC_MODE_ID] = "MODE_ID",
190 [IGT_CRTC_ACTIVE] = "ACTIVE",
191 [IGT_CRTC_OUT_FENCE_PTR] = "OUT_FENCE_PTR",
Nicholas Kazlauskasd1bd9c62019-01-28 10:44:18 -0500192 [IGT_CRTC_VRR_ENABLED] = "VRR_ENABLED",
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530193};
194
Ville Syrjälä837fea22018-03-05 22:12:58 +0200195const char * const igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
Ville Syrjäläc30e3312018-03-05 22:08:21 +0200196 [IGT_CONNECTOR_SCALING_MODE] = "scaling mode",
197 [IGT_CONNECTOR_CRTC_ID] = "CRTC_ID",
198 [IGT_CONNECTOR_DPMS] = "DPMS",
199 [IGT_CONNECTOR_BROADCAST_RGB] = "Broadcast RGB",
Ramalingam C7889b6a2018-10-22 22:35:40 +0530200 [IGT_CONNECTOR_CONTENT_PROTECTION] = "Content Protection",
Nicholas Kazlauskasd1bd9c62019-01-28 10:44:18 -0500201 [IGT_CONNECTOR_VRR_CAPABLE] = "vrr_capable",
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530202};
203
204/*
205 * Retrieve all the properies specified in props_name and store them into
Maarten Lankhorst5e42c622017-09-21 14:30:09 +0200206 * plane->props.
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530207 */
208static void
Maarten Lankhorst5e42c622017-09-21 14:30:09 +0200209igt_fill_plane_props(igt_display_t *display, igt_plane_t *plane,
Ville Syrjälä837fea22018-03-05 22:12:58 +0200210 int num_props, const char * const prop_names[])
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530211{
212 drmModeObjectPropertiesPtr props;
213 int i, j, fd;
214
215 fd = display->drm_fd;
216
217 props = drmModeObjectGetProperties(fd, plane->drm_plane->plane_id, DRM_MODE_OBJECT_PLANE);
218 igt_assert(props);
219
220 for (i = 0; i < props->count_props; i++) {
221 drmModePropertyPtr prop =
222 drmModeGetProperty(fd, props->props[i]);
223
224 for (j = 0; j < num_props; j++) {
225 if (strcmp(prop->name, prop_names[j]) != 0)
226 continue;
227
Maarten Lankhorst5e42c622017-09-21 14:30:09 +0200228 plane->props[j] = props->props[i];
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530229 break;
230 }
231
232 drmModeFreeProperty(prop);
233 }
234
235 drmModeFreeObjectProperties(props);
236}
237
238/*
239 * Retrieve all the properies specified in props_name and store them into
Maarten Lankhorst0404de42016-06-29 15:56:28 +0200240 * config->atomic_props_crtc and config->atomic_props_connector.
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530241 */
242static void
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200243igt_atomic_fill_connector_props(igt_display_t *display, igt_output_t *output,
Ville Syrjälä837fea22018-03-05 22:12:58 +0200244 int num_connector_props, const char * const conn_prop_names[])
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530245{
246 drmModeObjectPropertiesPtr props;
247 int i, j, fd;
248
249 fd = display->drm_fd;
250
Maarten Lankhorst0404de42016-06-29 15:56:28 +0200251 props = drmModeObjectGetProperties(fd, output->config.connector->connector_id, DRM_MODE_OBJECT_CONNECTOR);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530252 igt_assert(props);
253
254 for (i = 0; i < props->count_props; i++) {
255 drmModePropertyPtr prop =
256 drmModeGetProperty(fd, props->props[i]);
257
258 for (j = 0; j < num_connector_props; j++) {
259 if (strcmp(prop->name, conn_prop_names[j]) != 0)
260 continue;
261
Maarten Lankhorst13ead622017-09-21 12:01:41 +0200262 output->props[j] = props->props[i];
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530263 break;
264 }
265
266 drmModeFreeProperty(prop);
267 }
268
269 drmModeFreeObjectProperties(props);
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200270}
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530271
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200272static void
Maarten Lankhorst66fb4662017-09-21 16:07:48 +0200273igt_fill_pipe_props(igt_display_t *display, igt_pipe_t *pipe,
Ville Syrjälä837fea22018-03-05 22:12:58 +0200274 int num_crtc_props, const char * const crtc_prop_names[])
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200275{
276 drmModeObjectPropertiesPtr props;
277 int i, j, fd;
278
279 fd = display->drm_fd;
280
281 props = drmModeObjectGetProperties(fd, pipe->crtc_id, DRM_MODE_OBJECT_CRTC);
282 igt_assert(props);
283
284 for (i = 0; i < props->count_props; i++) {
285 drmModePropertyPtr prop =
286 drmModeGetProperty(fd, props->props[i]);
287
288 for (j = 0; j < num_crtc_props; j++) {
289 if (strcmp(prop->name, crtc_prop_names[j]) != 0)
290 continue;
291
Maarten Lankhorst66fb4662017-09-21 16:07:48 +0200292 pipe->props[j] = props->props[i];
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +0200293 break;
294 }
295
296 drmModeFreeProperty(prop);
297 }
298
299 drmModeFreeObjectProperties(props);
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +0530300}
301
Gustavo Padovanedf4f1f2016-10-26 11:56:47 +0000302/**
303 * igt_kms_get_alt_edid:
304 *
305 * Get an alternate edid block, which includes the following modes:
306 *
307 * - 1400x1050 60Hz
308 * - 1920x1080 60Hz
309 * - 1280x720 60Hz
310 * - 1024x768 60Hz
311 * - 800x600 60Hz
312 * - 640x480 60Hz
313 *
314 * This can be extended with further features using functions such as
315 * #kmstest_edid_add_3d.
316 *
317 * Returns: an alternate edid block
318 */
Ville Syrjälä870548b2015-12-04 15:49:30 +0200319const unsigned char* igt_kms_get_alt_edid(void)
320{
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +0300321 update_edid_csum(alt_edid, 0);
Ville Syrjälä870548b2015-12-04 15:49:30 +0200322
323 return alt_edid;
324}
Thomas Wood273a06d2014-10-08 14:11:30 +0100325
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +0100326/**
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200327 * kmstest_pipe_name:
328 * @pipe: display pipe
329 *
Robert Foss3b453f72017-01-10 13:33:41 -0500330 * Returns: String representing @pipe, e.g. "A".
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200331 */
332const char *kmstest_pipe_name(enum pipe pipe)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000333{
Lucas De Marchi25362a32018-06-06 15:27:41 -0700334 static const char str[] = "A\0B\0C\0D\0E\0F";
335
336 _Static_assert(sizeof(str) == IGT_MAX_PIPES * 2,
337 "Missing pipe name");
Oscar Mateo37f26d12013-11-12 11:50:38 +0000338
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +0200339 if (pipe == PIPE_NONE)
340 return "None";
341
Leo (Sunpeng) Lidf682172017-06-09 17:13:04 -0400342 if (pipe >= IGT_MAX_PIPES)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000343 return "invalid";
344
Lucas De Marchi25362a32018-06-06 15:27:41 -0700345 return str + (pipe * 2);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000346}
347
Daniel Vetter27a19de2014-08-12 11:04:49 +0200348/**
Mika Kahola12e34d82016-11-23 11:19:37 +0200349 * kmstest_pipe_to_index:
350 *@pipe: display pipe in string format
351 *
352 * Returns: index to corresponding pipe
353 */
354int kmstest_pipe_to_index(char pipe)
355{
Lucas De Marchi25362a32018-06-06 15:27:41 -0700356 int r = pipe - 'A';
357
358 if (r < 0 || r >= IGT_MAX_PIPES)
Mika Kahola12e34d82016-11-23 11:19:37 +0200359 return -EINVAL;
Lucas De Marchi25362a32018-06-06 15:27:41 -0700360
361 return r;
Mika Kahola12e34d82016-11-23 11:19:37 +0200362}
363
364/**
Robert Foss36656232017-01-18 12:28:45 -0500365 * kmstest_plane_type_name:
Maarten Lankhorsta79c8502018-02-21 11:10:16 +0100366 * @plane_type: display plane type
Robert Foss36656232017-01-18 12:28:45 -0500367 *
Maarten Lankhorsta79c8502018-02-21 11:10:16 +0100368 * Returns: String representing @plane_type, e.g. "overlay".
Robert Foss36656232017-01-18 12:28:45 -0500369 */
370const char *kmstest_plane_type_name(int plane_type)
371{
Ville Syrjälä837fea22018-03-05 22:12:58 +0200372 static const char * const names[] = {
Robert Foss36656232017-01-18 12:28:45 -0500373 [DRM_PLANE_TYPE_OVERLAY] = "overlay",
374 [DRM_PLANE_TYPE_PRIMARY] = "primary",
375 [DRM_PLANE_TYPE_CURSOR] = "cursor",
376 };
377
378 igt_assert(plane_type < ARRAY_SIZE(names) && names[plane_type]);
379
380 return names[plane_type];
381}
382
Arkadiusz Hiler430946d2017-11-24 17:17:47 +0200383struct type_name {
384 int type;
385 const char *name;
386};
387
388static const char *find_type_name(const struct type_name *names, int type)
389{
390 for (; names->name; names++) {
391 if (names->type == type)
392 return names->name;
393 }
394
395 return "(invalid)";
396}
397
398static const struct type_name encoder_type_names[] = {
399 { DRM_MODE_ENCODER_NONE, "none" },
400 { DRM_MODE_ENCODER_DAC, "DAC" },
401 { DRM_MODE_ENCODER_TMDS, "TMDS" },
402 { DRM_MODE_ENCODER_LVDS, "LVDS" },
403 { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
404 { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
405 { DRM_MODE_ENCODER_DSI, "DSI" },
406 { DRM_MODE_ENCODER_DPMST, "DP MST" },
407 {}
408};
409
410/**
411 * kmstest_encoder_type_str:
412 * @type: DRM_MODE_ENCODER_* enumeration value
413 *
414 * Returns: A string representing the drm encoder @type.
415 */
416const char *kmstest_encoder_type_str(int type)
417{
418 return find_type_name(encoder_type_names, type);
419}
420
421static const struct type_name connector_status_names[] = {
422 { DRM_MODE_CONNECTED, "connected" },
423 { DRM_MODE_DISCONNECTED, "disconnected" },
424 { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
425 {}
426};
427
428/**
429 * kmstest_connector_status_str:
430 * @status: DRM_MODE_* connector status value
431 *
432 * Returns: A string representing the drm connector status @status.
433 */
434const char *kmstest_connector_status_str(int status)
435{
436 return find_type_name(connector_status_names, status);
437}
438
439static const struct type_name connector_type_names[] = {
440 { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
441 { DRM_MODE_CONNECTOR_VGA, "VGA" },
442 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
443 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
444 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
445 { DRM_MODE_CONNECTOR_Composite, "Composite" },
446 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
447 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
448 { DRM_MODE_CONNECTOR_Component, "Component" },
449 { DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
450 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
451 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
452 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
453 { DRM_MODE_CONNECTOR_TV, "TV" },
454 { DRM_MODE_CONNECTOR_eDP, "eDP" },
455 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
456 { DRM_MODE_CONNECTOR_DSI, "DSI" },
457 { DRM_MODE_CONNECTOR_DPI, "DPI" },
458 {}
459};
460
461/**
462 * kmstest_connector_type_str:
463 * @type: DRM_MODE_CONNECTOR_* enumeration value
464 *
465 * Returns: A string representing the drm connector @type.
466 */
467const char *kmstest_connector_type_str(int type)
468{
469 return find_type_name(connector_type_names, type);
470}
471
Oscar Mateo37f26d12013-11-12 11:50:38 +0000472static const char *mode_stereo_name(const drmModeModeInfo *mode)
473{
474 switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
475 case DRM_MODE_FLAG_3D_FRAME_PACKING:
476 return "FP";
477 case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
478 return "FA";
479 case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
480 return "LA";
481 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
482 return "SBSF";
483 case DRM_MODE_FLAG_3D_L_DEPTH:
484 return "LD";
485 case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
486 return "LDGFX";
487 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
488 return "TB";
489 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
490 return "SBSH";
491 default:
492 return NULL;
493 }
494}
495
Daniel Vetter27a19de2014-08-12 11:04:49 +0200496/**
497 * kmstest_dump_mode:
498 * @mode: libdrm mode structure
499 *
Ville Syrjälä9afd5452016-08-05 13:36:42 +0300500 * Prints @mode to stdout in a human-readable form.
Daniel Vetter27a19de2014-08-12 11:04:49 +0200501 */
Oscar Mateo37f26d12013-11-12 11:50:38 +0000502void kmstest_dump_mode(drmModeModeInfo *mode)
503{
504 const char *stereo = mode_stereo_name(mode);
505
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200506 igt_info(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s\n",
507 mode->name, mode->vrefresh,
508 mode->hdisplay, mode->hsync_start,
509 mode->hsync_end, mode->htotal,
510 mode->vdisplay, mode->vsync_start,
511 mode->vsync_end, mode->vtotal,
512 mode->flags, mode->type, mode->clock,
513 stereo ? " (3D:" : "",
514 stereo ? stereo : "", stereo ? ")" : "");
Oscar Mateo37f26d12013-11-12 11:50:38 +0000515}
516
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200517/**
518 * kmstest_get_pipe_from_crtc_id:
519 * @fd: DRM fd
520 * @crtc_id: DRM CRTC id
521 *
Micah Fedkebe354f42016-03-09 16:57:37 +0100522 * Returns: The crtc index for the given DRM CRTC ID @crtc_id. The crtc index
523 * is the equivalent of the pipe id. This value maps directly to an enum pipe
524 * value used in other helper functions. Returns 0 if the index could not be
525 * determined.
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200526 */
Micah Fedkebe354f42016-03-09 16:57:37 +0100527
Oscar Mateo37f26d12013-11-12 11:50:38 +0000528int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
529{
Micah Fedkebe354f42016-03-09 16:57:37 +0100530 drmModeRes *res;
531 drmModeCrtc *crtc;
532 int i, cur_id;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000533
Micah Fedkebe354f42016-03-09 16:57:37 +0100534 res = drmModeGetResources(fd);
535 igt_assert(res);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000536
Micah Fedkebe354f42016-03-09 16:57:37 +0100537 for (i = 0; i < res->count_crtcs; i++) {
538 crtc = drmModeGetCrtc(fd, res->crtcs[i]);
539 igt_assert(crtc);
540 cur_id = crtc->crtc_id;
541 drmModeFreeCrtc(crtc);
542 if (cur_id == crtc_id)
543 break;
544 }
545
Micah Fedkebe354f42016-03-09 16:57:37 +0100546 igt_assert(i < res->count_crtcs);
547
Tvrtko Ursulin1aebeeb2016-04-27 15:58:24 +0100548 drmModeFreeResources(res);
549
Micah Fedkebe354f42016-03-09 16:57:37 +0100550 return i;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000551}
552
Paulo Zanonid8bf28f2016-02-26 11:27:20 -0300553/**
554 * kmstest_find_crtc_for_connector:
555 * @fd: DRM fd
556 * @res: libdrm resources pointer
557 * @connector: libdrm connector pointer
558 * @crtc_blacklist_idx_mask: a mask of CRTC indexes that we can't return
559 *
560 * Returns: the CRTC ID for a CRTC that fits the connector, otherwise it asserts
561 * false and never returns. The blacklist mask can be used in case you have
562 * CRTCs that are already in use by other connectors.
563 */
564uint32_t kmstest_find_crtc_for_connector(int fd, drmModeRes *res,
565 drmModeConnector *connector,
566 uint32_t crtc_blacklist_idx_mask)
567{
568 drmModeEncoder *e;
569 uint32_t possible_crtcs;
570 int i, j;
571
572 for (i = 0; i < connector->count_encoders; i++) {
573 e = drmModeGetEncoder(fd, connector->encoders[i]);
574 possible_crtcs = e->possible_crtcs & ~crtc_blacklist_idx_mask;
575 drmModeFreeEncoder(e);
576
577 for (j = 0; possible_crtcs >> j; j++)
578 if (possible_crtcs & (1 << j))
579 return res->crtcs[j];
580 }
581
582 igt_assert(false);
583}
584
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100585/**
586 * kmstest_dumb_create:
587 * @fd: open drm file descriptor
588 * @width: width of the buffer in pixels
589 * @height: height of the buffer in pixels
590 * @bpp: bytes per pixel of the buffer
Maarten Lankhorst2d672a12016-07-27 15:33:12 +0200591 * @stride: Pointer which receives the dumb bo's stride, can be NULL.
592 * @size: Pointer which receives the dumb bo's size, can be NULL.
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100593 *
594 * This wraps the CREATE_DUMB ioctl, which allocates a new dumb buffer object
595 * for the specified dimensions.
596 *
597 * Returns: The file-private handle of the created buffer object
598 */
599uint32_t kmstest_dumb_create(int fd, int width, int height, int bpp,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300600 unsigned *stride, uint64_t *size)
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100601{
602 struct drm_mode_create_dumb create;
603
604 memset(&create, 0, sizeof(create));
605 create.width = width;
606 create.height = height;
607 create.bpp = bpp;
608
609 create.handle = 0;
610 do_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
611 igt_assert(create.handle);
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300612 igt_assert(create.size >= (uint64_t) width * height * bpp / 8);
Tomeu Vizosodc84e7d2016-03-02 13:39:44 +0100613
614 if (stride)
615 *stride = create.pitch;
616
617 if (size)
618 *size = create.size;
619
620 return create.handle;
621}
622
Carlos Santadf09cb52018-02-12 15:45:23 -0800623/**
624 * kmstest_dumb_map_buffer:
625 * @fd: Opened drm file descriptor
626 * @handle: Offset in the file referred to by fd
627 * @size: Length of the mapping, must be greater than 0
628 * @prot: Describes the memory protection of the mapping
629 * Returns: A pointer representing the start of the virtual mapping
630 */
Tomeu Vizosofb66a5d2016-03-07 16:37:36 +0100631void *kmstest_dumb_map_buffer(int fd, uint32_t handle, uint64_t size,
632 unsigned prot)
633{
634 struct drm_mode_map_dumb arg = {};
635 void *ptr;
636
637 arg.handle = handle;
638
639 do_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
640
641 ptr = mmap(NULL, size, prot, MAP_SHARED, fd, arg.offset);
642 igt_assert(ptr != MAP_FAILED);
643
644 return ptr;
645}
646
Deepak Rawat4ca3d1d2018-10-16 15:23:37 -0700647static int __kmstest_dumb_destroy(int fd, uint32_t handle)
648{
649 struct drm_mode_destroy_dumb arg = { handle };
650 int err = 0;
651
652 if (drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg))
653 err = -errno;
654
655 errno = 0;
656 return err;
657}
658
659/**
660 * kmstest_dumb_destroy:
661 * @fd: Opened drm file descriptor
662 * @handle: Offset in the file referred to by fd
663 */
664void kmstest_dumb_destroy(int fd, uint32_t handle)
665{
666 igt_assert_eq(__kmstest_dumb_destroy(fd, handle), 0);
667}
668
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800669/*
670 * Returns: the previous mode, or KD_GRAPHICS if no /dev/tty0 was
671 * found and nothing was done.
672 */
Oscar Mateo37f26d12013-11-12 11:50:38 +0000673static signed long set_vt_mode(unsigned long mode)
674{
675 int fd;
676 unsigned long prev_mode;
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800677 static const char TTY0[] = "/dev/tty0";
Oscar Mateo37f26d12013-11-12 11:50:38 +0000678
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800679 if (access(TTY0, F_OK)) {
680 /* errno message should be "No such file". Do not
681 hardcode but ask strerror() in the very unlikely
682 case something else happened. */
683 igt_debug("VT: %s: %s, cannot change its mode\n",
684 TTY0, strerror(errno));
685 return KD_GRAPHICS;
686 }
687
688 fd = open(TTY0, O_RDONLY);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000689 if (fd < 0)
690 return -errno;
691
692 prev_mode = 0;
693 if (drmIoctl(fd, KDGETMODE, &prev_mode))
694 goto err;
695 if (drmIoctl(fd, KDSETMODE, (void *)mode))
696 goto err;
697
698 close(fd);
699
700 return prev_mode;
701err:
702 close(fd);
703
704 return -errno;
705}
706
707static unsigned long orig_vt_mode = -1UL;
708
Thomas Woodfcb324c2014-08-14 13:59:02 +0100709/**
710 * kmstest_restore_vt_mode:
711 *
712 * Restore the VT mode in use before #kmstest_set_vt_graphics_mode was called.
713 */
714void kmstest_restore_vt_mode(void)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000715{
Thomas Woodfcb324c2014-08-14 13:59:02 +0100716 long ret;
717
718 if (orig_vt_mode != -1UL) {
719 ret = set_vt_mode(orig_vt_mode);
Thomas Woodfcb324c2014-08-14 13:59:02 +0100720
721 igt_assert(ret >= 0);
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800722 igt_debug("VT: original mode 0x%lx restored\n", orig_vt_mode);
723 orig_vt_mode = -1UL;
Thomas Woodfcb324c2014-08-14 13:59:02 +0100724 }
Oscar Mateo37f26d12013-11-12 11:50:38 +0000725}
726
Daniel Vetter33f08842014-08-12 11:23:09 +0200727/**
728 * kmstest_set_vt_graphics_mode:
729 *
Thomas Woodfcb324c2014-08-14 13:59:02 +0100730 * Sets the controlling VT (if available) into graphics/raw mode and installs
731 * an igt exit handler to set the VT back to text mode on exit. Use
732 * #kmstest_restore_vt_mode to restore the previous VT mode manually.
Daniel Vetter33f08842014-08-12 11:23:09 +0200733 *
734 * All kms tests must call this function to make sure that the fbcon doesn't
735 * interfere by e.g. blanking the screen.
Oscar Mateo37f26d12013-11-12 11:50:38 +0000736 */
Daniel Vetter33f08842014-08-12 11:23:09 +0200737void kmstest_set_vt_graphics_mode(void)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000738{
Thomas Wood0269d1d2014-02-06 16:31:54 +0000739 long ret;
740
Thomas Woodfcb324c2014-08-14 13:59:02 +0100741 igt_install_exit_handler((igt_exit_handler_t) kmstest_restore_vt_mode);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000742
Thomas Wood0269d1d2014-02-06 16:31:54 +0000743 ret = set_vt_mode(KD_GRAPHICS);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000744
Thomas Wood0269d1d2014-02-06 16:31:54 +0000745 igt_assert(ret >= 0);
746 orig_vt_mode = ret;
Thomas Woodfcb324c2014-08-14 13:59:02 +0100747
Marc Herbertc6d18ee2015-02-24 12:29:22 -0800748 igt_debug("VT: graphics mode set (mode was 0x%lx)\n", ret);
Oscar Mateo37f26d12013-11-12 11:50:38 +0000749}
750
Thomas Woodc76f3532014-12-03 14:38:45 +0000751
752static void reset_connectors_at_exit(int sig)
753{
754 igt_reset_connectors();
755}
756
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200757/**
758 * kmstest_force_connector:
759 * @fd: drm file descriptor
760 * @connector: connector
761 * @state: state to force on @connector
762 *
763 * Force the specified state on the specified connector.
764 *
765 * Returns: true on success
766 */
767bool kmstest_force_connector(int drm_fd, drmModeConnector *connector,
768 enum kmstest_force_connector_state state)
769{
Thomas Woodf675f672014-09-04 11:35:01 +0100770 char *path, **tmp;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200771 const char *value;
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100772 drmModeConnector *temp;
Thomas Woodd3c83b22014-09-04 16:56:17 +0100773 uint32_t devid;
Chris Wilson0e11bef2016-05-26 15:06:30 +0100774 int len, dir, idx;
Thomas Woodd3c83b22014-09-04 16:56:17 +0100775
Lyude81677442016-11-21 17:32:39 -0500776 if (is_i915_device(drm_fd)) {
777 devid = intel_get_drm_devid(drm_fd);
Thomas Woodd3c83b22014-09-04 16:56:17 +0100778
Lyude81677442016-11-21 17:32:39 -0500779 /*
780 * forcing hdmi or dp connectors on HSW and BDW doesn't
781 * currently work, so fail early to allow the test to skip if
782 * required
783 */
784 if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
785 connector->connector_type == DRM_MODE_CONNECTOR_HDMIB ||
786 connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
787 && (IS_HASWELL(devid) || IS_BROADWELL(devid)))
788 return false;
789 }
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200790
791 switch (state) {
792 case FORCE_CONNECTOR_ON:
793 value = "on";
794 break;
795 case FORCE_CONNECTOR_DIGITAL:
Chris Wilson0e11bef2016-05-26 15:06:30 +0100796 value = "on-digital";
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200797 break;
798 case FORCE_CONNECTOR_OFF:
799 value = "off";
800 break;
801
802 default:
803 case FORCE_CONNECTOR_UNSPECIFIED:
Chris Wilson0e11bef2016-05-26 15:06:30 +0100804 value = "detect";
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200805 break;
806 }
807
Chris Wilson0e11bef2016-05-26 15:06:30 +0100808 dir = igt_sysfs_open(drm_fd, &idx);
809 if (dir < 0)
810 return false;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200811
Chris Wilson0e11bef2016-05-26 15:06:30 +0100812 if (asprintf(&path, "card%d-%s-%d/status",
813 idx,
814 kmstest_connector_type_str(connector->connector_type),
815 connector->connector_type_id) < 0) {
816 close(dir);
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200817 return false;
818 }
819
Marius Vlad32940a02016-06-03 20:51:10 +0300820 if (!igt_sysfs_set(dir, path, value)) {
Chris Wilson0e11bef2016-05-26 15:06:30 +0100821 close(dir);
822 return false;
823 }
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200824
Thomas Woodf675f672014-09-04 11:35:01 +0100825 for (len = 0, tmp = forced_connectors; *tmp; tmp++) {
826 /* check the connector is not already present */
827 if (strcmp(*tmp, path) == 0) {
828 len = -1;
829 break;
830 }
831 len++;
832 }
833
Chris Wilson0e11bef2016-05-26 15:06:30 +0100834 if (len != -1 && len < MAX_CONNECTORS) {
Thomas Woodf675f672014-09-04 11:35:01 +0100835 forced_connectors[len] = path;
Chris Wilson0e11bef2016-05-26 15:06:30 +0100836 forced_connectors_device[len] = dir;
837 }
Thomas Woodf675f672014-09-04 11:35:01 +0100838
839 if (len >= MAX_CONNECTORS)
840 igt_warn("Connector limit reached, %s will not be reset\n",
841 path);
842
843 igt_debug("Connector %s is now forced %s\n", path, value);
844 igt_debug("Current forced connectors:\n");
845 tmp = forced_connectors;
846 while (*tmp) {
847 igt_debug("\t%s\n", *tmp);
848 tmp++;
849 }
850
Thomas Woodc76f3532014-12-03 14:38:45 +0000851 igt_install_exit_handler(reset_connectors_at_exit);
Thomas Woodf675f672014-09-04 11:35:01 +0100852
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100853 /* To allow callers to always use GetConnectorCurrent we need to force a
854 * redetection here. */
855 temp = drmModeGetConnector(drm_fd, connector->connector_id);
856 drmModeFreeConnector(temp);
857
Chris Wilson0e11bef2016-05-26 15:06:30 +0100858 return true;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200859}
860
861/**
862 * kmstest_force_edid:
863 * @drm_fd: drm file descriptor
864 * @connector: connector to set @edid on
865 * @edid: An EDID data block
866 * @length: length of the EDID data. #EDID_LENGTH defines the standard EDID
867 * length
868 *
Thomas Wood8d82e5b2014-10-08 16:16:39 +0100869 * Set the EDID data on @connector to @edid. See also #igt_kms_get_base_edid.
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200870 *
871 * If @length is zero, the forced EDID will be removed.
872 */
873void kmstest_force_edid(int drm_fd, drmModeConnector *connector,
874 const unsigned char *edid, size_t length)
875{
876 char *path;
877 int debugfs_fd, ret;
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100878 drmModeConnector *temp;
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200879
Thomas Wood47f6b132015-03-25 16:42:57 +0000880 igt_assert_neq(asprintf(&path, "%s-%d/edid_override", kmstest_connector_type_str(connector->connector_type), connector->connector_type_id),
881 -1);
Chris Wilson83884e92017-03-21 17:16:03 +0000882 debugfs_fd = igt_debugfs_open(drm_fd, path, O_WRONLY | O_TRUNC);
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200883 free(path);
884
Chris Wilson9b064012018-07-23 14:35:09 +0100885 igt_require(debugfs_fd != -1);
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200886
887 if (length == 0)
888 ret = write(debugfs_fd, "reset", 5);
889 else
890 ret = write(debugfs_fd, edid, length);
891 close(debugfs_fd);
892
Daniel Vetterdb4f83c2015-12-01 11:24:19 +0100893 /* To allow callers to always use GetConnectorCurrent we need to force a
894 * redetection here. */
895 temp = drmModeGetConnector(drm_fd, connector->connector_id);
896 drmModeFreeConnector(temp);
897
Daniel Vetter3b39bff2014-08-12 11:31:44 +0200898 igt_assert(ret != -1);
899}
900
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200901/**
902 * kmstest_get_connector_default_mode:
903 * @drm_fd: DRM fd
904 * @connector: libdrm connector
905 * @mode: libdrm mode
906 *
907 * Retrieves the default mode for @connector and stores it in @mode.
908 *
909 * Returns: true on success, false on failure
910 */
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200911bool kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
912 drmModeModeInfo *mode)
Oscar Mateo37f26d12013-11-12 11:50:38 +0000913{
Oscar Mateo37f26d12013-11-12 11:50:38 +0000914 int i;
915
Oscar Mateo37f26d12013-11-12 11:50:38 +0000916 if (!connector->count_modes) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +0200917 igt_warn("no modes for connector %d\n",
918 connector->connector_id);
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200919 return false;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000920 }
921
922 for (i = 0; i < connector->count_modes; i++) {
923 if (i == 0 ||
924 connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
925 *mode = connector->modes[i];
926 if (mode->type & DRM_MODE_TYPE_PREFERRED)
927 break;
928 }
929 }
930
Daniel Vetter81dfcab2014-08-12 11:56:41 +0200931 return true;
Oscar Mateo37f26d12013-11-12 11:50:38 +0000932}
933
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +0200934static void
935_kmstest_connector_config_crtc_mask(int drm_fd,
936 drmModeConnector *connector,
937 struct kmstest_connector_config *config)
938{
939 int i;
940
941 config->valid_crtc_idx_mask = 0;
942
943 /* Now get a compatible encoder */
944 for (i = 0; i < connector->count_encoders; i++) {
945 drmModeEncoder *encoder = drmModeGetEncoder(drm_fd,
946 connector->encoders[i]);
947
948 if (!encoder) {
949 igt_warn("could not get encoder %d: %s\n",
950 connector->encoders[i],
951 strerror(errno));
952
953 continue;
954 }
955
956 config->valid_crtc_idx_mask |= encoder->possible_crtcs;
957 drmModeFreeEncoder(encoder);
958 }
959}
960
961static drmModeEncoder *
962_kmstest_connector_config_find_encoder(int drm_fd, drmModeConnector *connector, enum pipe pipe)
963{
964 int i;
965
966 for (i = 0; i < connector->count_encoders; i++) {
967 drmModeEncoder *encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
968
969 if (!encoder) {
970 igt_warn("could not get encoder %d: %s\n",
971 connector->encoders[i],
972 strerror(errno));
973
974 continue;
975 }
976
977 if (encoder->possible_crtcs & (1 << pipe))
978 return encoder;
979
980 drmModeFreeEncoder(encoder);
981 }
982
983 igt_assert(false);
984 return NULL;
985}
986
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200987/**
Jesse Barnese28acef2016-01-14 14:03:53 -0800988 * _kmstest_connector_config:
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200989 * @drm_fd: DRM fd
990 * @connector_id: DRM connector id
991 * @crtc_idx_mask: mask of allowed DRM CRTC indices
992 * @config: structure filled with the possible configuration
Jesse Barnese28acef2016-01-14 14:03:53 -0800993 * @probe: whether to fully re-probe mode list or not
Daniel Vetter5c7bcb12014-08-12 12:10:20 +0200994 *
995 * This tries to find a suitable configuration for the given connector and CRTC
996 * constraint and fills it into @config.
997 */
Jesse Barnese28acef2016-01-14 14:03:53 -0800998static bool _kmstest_connector_config(int drm_fd, uint32_t connector_id,
999 unsigned long crtc_idx_mask,
1000 struct kmstest_connector_config *config,
1001 bool probe)
Oscar Mateo37f26d12013-11-12 11:50:38 +00001002{
1003 drmModeRes *resources;
1004 drmModeConnector *connector;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001005
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001006 config->pipe = PIPE_NONE;
1007
Oscar Mateo37f26d12013-11-12 11:50:38 +00001008 resources = drmModeGetResources(drm_fd);
1009 if (!resources) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +02001010 igt_warn("drmModeGetResources failed");
Oscar Mateo37f26d12013-11-12 11:50:38 +00001011 goto err1;
1012 }
1013
1014 /* First, find the connector & mode */
Jesse Barnese28acef2016-01-14 14:03:53 -08001015 if (probe)
1016 connector = drmModeGetConnector(drm_fd, connector_id);
1017 else
1018 connector = drmModeGetConnectorCurrent(drm_fd, connector_id);
1019
Oscar Mateo37f26d12013-11-12 11:50:38 +00001020 if (!connector)
1021 goto err2;
1022
Oscar Mateo37f26d12013-11-12 11:50:38 +00001023 if (connector->connector_id != connector_id) {
Daniel Vetter1649ef0d2014-08-26 15:26:21 +02001024 igt_warn("connector id doesn't match (%d != %d)\n",
1025 connector->connector_id, connector_id);
Oscar Mateo37f26d12013-11-12 11:50:38 +00001026 goto err3;
1027 }
1028
1029 /*
1030 * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
1031 * In both cases find the first compatible encoder and skip the CRTC
1032 * if there is non such.
1033 */
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +02001034 _kmstest_connector_config_crtc_mask(drm_fd, connector, config);
Maarten Lankhorst4a185972016-06-28 14:28:20 +02001035
Maarten Lankhorste511fab2016-08-25 09:08:34 +02001036 if (!connector->count_modes)
1037 memset(&config->default_mode, 0, sizeof(config->default_mode));
1038 else if (!kmstest_get_connector_default_mode(drm_fd, connector,
1039 &config->default_mode))
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +02001040 goto err3;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001041
1042 config->connector = connector;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001043
1044 crtc_idx_mask &= config->valid_crtc_idx_mask;
1045 if (!crtc_idx_mask)
1046 /* Keep config->connector */
1047 goto err2;
1048
1049 config->pipe = ffs(crtc_idx_mask) - 1;
1050
1051 config->encoder = _kmstest_connector_config_find_encoder(drm_fd, connector, config->pipe);
Maarten Lankhorst7d5449d2016-06-30 07:10:18 +02001052 config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[config->pipe]);
Oscar Mateo37f26d12013-11-12 11:50:38 +00001053
Maarten Lankhorste511fab2016-08-25 09:08:34 +02001054 if (connector->connection != DRM_MODE_CONNECTED)
1055 goto err2;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001056
Maarten Lankhorste511fab2016-08-25 09:08:34 +02001057 if (!connector->count_modes) {
Maarten Lankhorst2c3e1ca2018-04-06 12:59:46 +02001058 if (probe)
1059 igt_warn("connector %d/%s-%d has no modes\n", connector_id,
1060 kmstest_connector_type_str(connector->connector_type),
1061 connector->connector_type_id);
Maarten Lankhorste511fab2016-08-25 09:08:34 +02001062 goto err2;
1063 }
1064
1065 drmModeFreeResources(resources);
Daniel Vetter1cad8342014-08-12 11:57:32 +02001066 return true;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001067err3:
Maarten Lankhorst0404de42016-06-29 15:56:28 +02001068 drmModeFreeConnector(connector);
Oscar Mateo37f26d12013-11-12 11:50:38 +00001069err2:
1070 drmModeFreeResources(resources);
1071err1:
Daniel Vetter1cad8342014-08-12 11:57:32 +02001072 return false;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001073}
1074
Daniel Vetter5c7bcb12014-08-12 12:10:20 +02001075/**
Jesse Barnese28acef2016-01-14 14:03:53 -08001076 * kmstest_get_connector_config:
1077 * @drm_fd: DRM fd
1078 * @connector_id: DRM connector id
1079 * @crtc_idx_mask: mask of allowed DRM CRTC indices
1080 * @config: structure filled with the possible configuration
1081 *
1082 * This tries to find a suitable configuration for the given connector and CRTC
1083 * constraint and fills it into @config.
1084 */
1085bool kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
1086 unsigned long crtc_idx_mask,
1087 struct kmstest_connector_config *config)
1088{
1089 return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
1090 config, 0);
1091}
1092
1093/**
1094 * kmstest_probe_connector_config:
1095 * @drm_fd: DRM fd
1096 * @connector_id: DRM connector id
1097 * @crtc_idx_mask: mask of allowed DRM CRTC indices
1098 * @config: structure filled with the possible configuration
1099 *
1100 * This tries to find a suitable configuration for the given connector and CRTC
1101 * constraint and fills it into @config, fully probing the connector in the
1102 * process.
1103 */
1104bool kmstest_probe_connector_config(int drm_fd, uint32_t connector_id,
1105 unsigned long crtc_idx_mask,
1106 struct kmstest_connector_config *config)
1107{
1108 return _kmstest_connector_config(drm_fd, connector_id, crtc_idx_mask,
1109 config, 1);
1110}
1111
1112/**
Daniel Vetter5c7bcb12014-08-12 12:10:20 +02001113 * kmstest_free_connector_config:
1114 * @config: connector configuration structure
1115 *
1116 * Free any resources in @config allocated in kmstest_get_connector_config().
1117 */
Oscar Mateo37f26d12013-11-12 11:50:38 +00001118void kmstest_free_connector_config(struct kmstest_connector_config *config)
1119{
1120 drmModeFreeCrtc(config->crtc);
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001121 config->crtc = NULL;
1122
Oscar Mateo37f26d12013-11-12 11:50:38 +00001123 drmModeFreeEncoder(config->encoder);
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001124 config->encoder = NULL;
1125
Oscar Mateo37f26d12013-11-12 11:50:38 +00001126 drmModeFreeConnector(config->connector);
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001127 config->connector = NULL;
Oscar Mateo37f26d12013-11-12 11:50:38 +00001128}
1129
Daniel Vetter5c7bcb12014-08-12 12:10:20 +02001130/**
1131 * kmstest_set_connector_dpms:
1132 * @fd: DRM fd
1133 * @connector: libdrm connector
1134 * @mode: DRM DPMS value
1135 *
1136 * This function sets the DPMS setting of @connector to @mode.
1137 */
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001138void kmstest_set_connector_dpms(int fd, drmModeConnector *connector, int mode)
1139{
1140 int i, dpms = 0;
1141 bool found_it = false;
1142
1143 for (i = 0; i < connector->count_props; i++) {
Chris Wilson1d227a42017-08-09 11:07:24 +01001144 struct drm_mode_get_property prop = {
1145 .prop_id = connector->props[i],
1146 };
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001147
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001148 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
1149 continue;
1150
1151 if (strcmp(prop.name, "DPMS"))
1152 continue;
1153
1154 dpms = prop.prop_id;
1155 found_it = true;
1156 break;
1157 }
1158 igt_assert_f(found_it, "DPMS property not found on %d\n",
1159 connector->connector_id);
1160
1161 igt_assert(drmModeConnectorSetProperty(fd, connector->connector_id,
1162 dpms, mode) == 0);
1163}
1164
1165/**
1166 * kmstest_get_property:
1167 * @drm_fd: drm file descriptor
1168 * @object_id: object whose properties we're going to get
1169 * @object_type: type of obj_id (DRM_MODE_OBJECT_*)
1170 * @name: name of the property we're going to get
1171 * @prop_id: if not NULL, returns the property id
1172 * @value: if not NULL, returns the property value
1173 * @prop: if not NULL, returns the property, and the caller will have to free
1174 * it manually.
1175 *
1176 * Finds a property with the given name on the given object.
1177 *
1178 * Returns: true in case we found something.
1179 */
1180bool
1181kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type,
1182 const char *name, uint32_t *prop_id /* out */,
1183 uint64_t *value /* out */,
1184 drmModePropertyPtr *prop /* out */)
1185{
1186 drmModeObjectPropertiesPtr proplist;
1187 drmModePropertyPtr _prop;
1188 bool found = false;
1189 int i;
1190
1191 proplist = drmModeObjectGetProperties(drm_fd, object_id, object_type);
1192 for (i = 0; i < proplist->count_props; i++) {
1193 _prop = drmModeGetProperty(drm_fd, proplist->props[i]);
1194 if (!_prop)
1195 continue;
1196
1197 if (strcmp(_prop->name, name) == 0) {
1198 found = true;
1199 if (prop_id)
1200 *prop_id = proplist->props[i];
1201 if (value)
1202 *value = proplist->prop_values[i];
1203 if (prop)
1204 *prop = _prop;
1205 else
1206 drmModeFreeProperty(_prop);
1207
1208 break;
1209 }
1210 drmModeFreeProperty(_prop);
1211 }
1212
1213 drmModeFreeObjectProperties(proplist);
1214 return found;
1215}
1216
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001217struct edid_block {
1218 int pos;
1219 unsigned char *data;
1220};
1221
1222#define DTD_SUPPORTS_AUDIO 1<<6
1223
1224static struct edid_block
1225init_cea_block(const unsigned char *edid, size_t length,
1226 unsigned char *new_edid_ptr[], size_t *new_length,
1227 char extra_extensions_length,
1228 uint32_t dtd_support)
1229{
1230 struct edid_block new_edid;
1231 int n_extensions;
1232 int pos;
1233 static const char cea_header_len = 4, video_block_len = 6;
1234
1235 igt_assert(new_edid_ptr != NULL && new_length != NULL);
1236
1237 *new_length = length + 128;
1238
Petri Latvalac5194742019-01-16 13:20:33 +02001239 new_edid.data = calloc(*new_length, sizeof(*new_edid.data));
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001240 igt_assert_f(new_edid.data, "Failed to allocate %zu bytes for edid\n", sizeof(new_length));
1241 memcpy(new_edid.data, edid, length);
1242 *new_edid_ptr = new_edid.data;
1243
1244 n_extensions = new_edid.data[126];
1245 n_extensions++;
1246 new_edid.data[126] = n_extensions;
1247
1248 update_edid_csum(new_edid.data, 0);
1249
1250 /* add a cea-861 extension block */
1251 pos = length;
1252 new_edid.data[pos++] = 0x2;
1253 new_edid.data[pos++] = 0x3;
1254 new_edid.data[pos++] = cea_header_len + video_block_len +
1255 extra_extensions_length;
1256 new_edid.data[pos++] = dtd_support;
1257
1258 /* video block (id | length) */
1259 new_edid.data[pos++] = 2 << 5 | (video_block_len - 1);
1260 new_edid.data[pos++] = 32 | 0x80; /* 1080p @ 24Hz | (native)*/
1261 new_edid.data[pos++] = 5; /* 1080i @ 60Hz */
1262 new_edid.data[pos++] = 20; /* 1080i @ 50Hz */
1263 new_edid.data[pos++] = 4; /* 720p @ 60Hz*/
1264 new_edid.data[pos++] = 19; /* 720p @ 50Hz*/
1265 new_edid.pos = pos;
1266
1267 return new_edid;
1268}
1269
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001270/**
Thomas Wooda124b1a2014-07-30 11:10:49 +01001271 * kmstest_edid_add_3d:
1272 * @edid: an existing valid edid block
1273 * @length: length of @edid
1274 * @new_edid_ptr: pointer to where the new edid will be placed
1275 * @new_length: pointer to the size of the new edid
1276 *
1277 * Makes a copy of an existing edid block and adds an extension indicating
1278 * stereo 3D capabilities.
1279 */
1280void kmstest_edid_add_3d(const unsigned char *edid, size_t length,
1281 unsigned char *new_edid_ptr[], size_t *new_length)
1282{
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001283 char vsdb_block_len = 11;
1284 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1285 new_length, vsdb_block_len,
1286 0);
1287 int pos = new_edid.pos;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001288
1289 /* vsdb block ( id | length ) */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001290 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
Thomas Wooda124b1a2014-07-30 11:10:49 +01001291 /* registration id */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001292 new_edid.data[pos++] = 0x3;
1293 new_edid.data[pos++] = 0xc;
1294 new_edid.data[pos++] = 0x0;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001295 /* source physical address */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001296 new_edid.data[pos++] = 0x10;
1297 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001298 /* Supports_AI ... etc */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001299 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001300 /* Max TMDS Clock */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001301 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001302 /* Latency present, HDMI Video Present */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001303 new_edid.data[pos++] = 0x20;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001304 /* HDMI Video */
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001305 new_edid.data[pos++] = 0x80;
1306 new_edid.data[pos++] = 0x00;
Thomas Wooda124b1a2014-07-30 11:10:49 +01001307
Abdiel Janulgue3cfa6a92017-03-27 12:47:08 +03001308 update_edid_csum(new_edid.data, length);
1309}
1310
1311/**
1312 * kmstest_edid_add_4k:
1313 * @edid: an existing valid edid block
1314 * @length: length of @edid
1315 * @new_edid_ptr: pointer to where the new edid will be placed
1316 * @new_length: pointer to the size of the new edid
1317 *
1318 * Makes a copy of an existing edid block and adds an extension indicating
1319 * a HDMI 4K mode in vsdb.
1320 */
1321void kmstest_edid_add_4k(const unsigned char *edid, size_t length,
1322 unsigned char *new_edid_ptr[], size_t *new_length)
1323{
1324 char vsdb_block_len = 12;
1325 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1326 new_length, vsdb_block_len,
1327 0);
1328 int pos = new_edid.pos;
1329
1330 /* vsdb block ( id | length ) */
1331 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
1332 /* registration id */
1333 new_edid.data[pos++] = 0x3;
1334 new_edid.data[pos++] = 0xc;
1335 new_edid.data[pos++] = 0x0;
1336 /* source physical address */
1337 new_edid.data[pos++] = 0x10;
1338 new_edid.data[pos++] = 0x00;
1339 /* Supports_AI ... etc */
1340 new_edid.data[pos++] = 0x00;
1341 /* Max TMDS Clock */
1342 new_edid.data[pos++] = 0x00;
1343 /* Latency present, HDMI Video Present */
1344 new_edid.data[pos++] = 0x20;
1345 /* HDMI Video */
1346 new_edid.data[pos++] = 0x00; /* 3D present */
1347
1348 /* HDMI MODE LEN -- how many entries */
1349 new_edid.data[pos++] = 0x20;
1350 /* 2160p, specified as short descriptor */
1351 new_edid.data[pos++] = 0x01;
1352
1353 update_edid_csum(new_edid.data, length);
1354}
1355
1356/**
1357 * kmstest_edid_add_audio:
1358 * @edid: an existing valid edid block
1359 * @length: length of @edid
1360 * @new_edid_ptr: pointer to where the new edid will be placed
1361 * @new_length: pointer to the size of the new edid
1362 *
1363 * Makes a copy of an existing edid block and adds an extension indicating
1364 * basic audio support and speaker data block.
1365 *
1366 */
1367void kmstest_edid_add_audio(const unsigned char *edid, size_t length,
1368 unsigned char *new_edid_ptr[], size_t *new_length)
1369{
1370 char vsdb_block_len = 10, audio_block_len = 4, spkr_block_len = 4;
1371 struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr,
1372 new_length,
1373 vsdb_block_len +
1374 audio_block_len +
1375 spkr_block_len,
1376 DTD_SUPPORTS_AUDIO);
1377 int pos = new_edid.pos;
1378
1379 /* audio block, short audio block descriptors */
1380 new_edid.data[pos++] = (1 << 5) | (audio_block_len - 1);
1381 new_edid.data[pos++] = 0x09; /* Audio Format, PCM */
1382 new_edid.data[pos++] = 0x07; /* Frequency, 32, 44.1, 48kHz */
1383 new_edid.data[pos++] = 0x07; /* Bit Rate 16, 20, 24 bit */
1384
1385
1386 /* vsdb block ( id | length ) -- need vsdb as well
1387 * otherwise the kernel will fallback to lower clock modes */
1388 new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1);
1389 /* registration id */
1390 new_edid.data[pos++] = 0x3;
1391 new_edid.data[pos++] = 0xc;
1392 new_edid.data[pos++] = 0x0;
1393 /* source physical address */
1394 new_edid.data[pos++] = 0x10;
1395 new_edid.data[pos++] = 0x00;
1396 /* Supports_AI ... etc */
1397 new_edid.data[pos++] = 0x00;
1398 /* Max TMDS Clock */
1399 new_edid.data[pos++] = 0x00;
1400 /* Latency present, HDMI Video Present */
1401 new_edid.data[pos++] = 0x20;
1402 /* HDMI Video */
1403 new_edid.data[pos++] = 0x00; /* 3D present */
1404
1405 /* speaker data block */
1406 new_edid.data[pos++] = (4 << 5) | (spkr_block_len - 1);
1407 new_edid.data[pos++] = (1 << 5);
1408 new_edid.data[pos++] = 0x00;
1409 new_edid.data[pos++] = 0x00;
1410
1411 update_edid_csum(new_edid.data, length);
Thomas Wooda124b1a2014-07-30 11:10:49 +01001412}
1413
1414/**
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001415 * kmstest_unset_all_crtcs:
1416 * @drm_fd: the DRM fd
1417 * @resources: libdrm resources pointer
1418 *
1419 * Disables all the screens.
1420 */
1421void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources)
1422{
1423 int i, rc;
1424
1425 for (i = 0; i < resources->count_crtcs; i++) {
Ville Syrjälä4d8983b2015-11-11 20:25:11 +02001426 rc = drmModeSetCrtc(drm_fd, resources->crtcs[i], 0, 0, 0, NULL,
Daniel Vetter3b39bff2014-08-12 11:31:44 +02001427 0, NULL);
1428 igt_assert(rc == 0);
1429 }
1430}
1431
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001432/**
Daniel Vetter483d1c02016-03-19 12:12:47 +01001433 * kmstest_get_crtc_idx:
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001434 * @res: the libdrm resources
1435 * @crtc_id: the CRTC id
1436 *
Daniel Vetter483d1c02016-03-19 12:12:47 +01001437 * Get the CRTC index based on its ID. This is useful since a few places of
1438 * libdrm deal with CRTC masks.
Paulo Zanonic6279ec2016-02-26 08:54:57 -03001439 */
1440int kmstest_get_crtc_idx(drmModeRes *res, uint32_t crtc_id)
1441{
1442 int i;
1443
1444 for (i = 0; i < res->count_crtcs; i++)
1445 if (res->crtcs[i] == crtc_id)
1446 return i;
1447
1448 igt_assert(false);
1449}
1450
Mika Kahola12e34d82016-11-23 11:19:37 +02001451static inline uint32_t pipe_select(int pipe)
1452{
1453 if (pipe > 1)
1454 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
1455 else if (pipe > 0)
1456 return DRM_VBLANK_SECONDARY;
1457 else
1458 return 0;
1459}
1460
Carlos Santadf09cb52018-02-12 15:45:23 -08001461/**
1462 * kmstest_get_vblank:
1463 * @fd: Opened drm file descriptor
1464 * @pipe: Display pipe
1465 * @flags: Flags passed to drm_ioctl_wait_vblank
1466 *
1467 * Blocks or request a signal when a specified vblank event occurs
1468 *
1469 * Returns 0 on success or non-zero unsigned integer otherwise
1470 */
Mika Kahola12e34d82016-11-23 11:19:37 +02001471unsigned int kmstest_get_vblank(int fd, int pipe, unsigned int flags)
1472{
1473 union drm_wait_vblank vbl;
1474
1475 memset(&vbl, 0, sizeof(vbl));
1476 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags;
1477 if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
1478 return 0;
1479
1480 return vbl.reply.sequence;
1481}
1482
Mika Kahola4d092022018-05-23 14:47:37 +03001483/**
1484 * kmstest_wait_for_pageflip:
1485 * @fd: Opened drm file descriptor
1486 *
1487 * Blocks until pageflip is completed
1488 *
1489 */
1490void kmstest_wait_for_pageflip(int fd)
1491{
1492 drmEventContext evctx = { .version = 2 };
1493 struct timeval timeout = { .tv_sec = 0, .tv_usec = 50000 };
1494 fd_set fds;
1495 int ret;
1496
1497 /* Wait for pageflip completion, then consume event on fd */
1498 FD_ZERO(&fds);
1499 FD_SET(fd, &fds);
1500 do {
1501 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
1502 } while (ret < 0 && errno == EINTR);
1503 igt_assert_eq(ret, 1);
1504 igt_assert(drmHandleEvent(fd, &evctx) == 0);
1505}
1506
Mika Kahola12e34d82016-11-23 11:19:37 +02001507static void get_plane(char *str, int type, struct kmstest_plane *plane)
1508{
1509 int ret;
1510 char buf[256];
1511
Robert Foss9de63592017-01-18 12:12:54 -05001512 plane->type = type;
Mika Kahola12e34d82016-11-23 11:19:37 +02001513 ret = sscanf(str + 12, "%d%*c %*s %[^n]s",
1514 &plane->id,
1515 buf);
1516 igt_assert_eq(ret, 2);
1517
1518 ret = sscanf(buf + 9, "%4d%*c%4d%*c", &plane->pos_x, &plane->pos_y);
1519 igt_assert_eq(ret, 2);
1520
1521 ret = sscanf(buf + 30, "%4d%*c%4d%*c", &plane->width, &plane->height);
1522 igt_assert_eq(ret, 2);
1523}
1524
Robert Foss9de63592017-01-18 12:12:54 -05001525static int parse_planes(FILE *fid, struct kmstest_plane *planes)
Mika Kahola12e34d82016-11-23 11:19:37 +02001526{
1527 char tmp[256];
Robert Foss9de63592017-01-18 12:12:54 -05001528 int n_planes;
Mika Kahola12e34d82016-11-23 11:19:37 +02001529
Robert Foss9de63592017-01-18 12:12:54 -05001530 n_planes = 0;
Mika Kahola12e34d82016-11-23 11:19:37 +02001531 while (fgets(tmp, 256, fid) != NULL) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001532 if (strstr(tmp, "type=PRI") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001533 if (planes) {
1534 get_plane(tmp, DRM_PLANE_TYPE_PRIMARY, &planes[n_planes]);
1535 planes[n_planes].index = n_planes;
1536 }
1537 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001538 } else if (strstr(tmp, "type=OVL") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001539 if (planes) {
1540 get_plane(tmp, DRM_PLANE_TYPE_OVERLAY, &planes[n_planes]);
1541 planes[n_planes].index = n_planes;
1542 }
1543 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001544 } else if (strstr(tmp, "type=CUR") != NULL) {
Robert Foss9de63592017-01-18 12:12:54 -05001545 if (planes) {
1546 get_plane(tmp, DRM_PLANE_TYPE_CURSOR, &planes[n_planes]);
1547 planes[n_planes].index = n_planes;
1548 }
1549 n_planes++;
Mika Kahola12e34d82016-11-23 11:19:37 +02001550 break;
1551 }
1552 }
1553
Robert Foss9de63592017-01-18 12:12:54 -05001554 return n_planes;
Mika Kahola12e34d82016-11-23 11:19:37 +02001555}
1556
1557static void parse_crtc(char *info, struct kmstest_crtc *crtc)
1558{
1559 char buf[256];
1560 int ret;
1561 char pipe;
1562
1563 ret = sscanf(info + 4, "%d%*c %*s %c%*c %*s %s%*c",
1564 &crtc->id, &pipe, buf);
1565 igt_assert_eq(ret, 3);
1566
1567 crtc->pipe = kmstest_pipe_to_index(pipe);
1568 igt_assert(crtc->pipe >= 0);
1569
1570 ret = sscanf(buf + 6, "%d%*c%d%*c",
1571 &crtc->width, &crtc->height);
1572 igt_assert_eq(ret, 2);
1573}
1574
Maarten Lankhorstcdfe9922017-10-13 14:04:38 +02001575static void kmstest_get_crtc(int device, enum pipe pipe, struct kmstest_crtc *crtc)
Mika Kahola12e34d82016-11-23 11:19:37 +02001576{
1577 char tmp[256];
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001578 FILE *file;
Mika Kahola12e34d82016-11-23 11:19:37 +02001579 int ncrtc;
1580 int line;
Mika Kahola11e31f92017-02-16 11:20:45 +02001581 long int n;
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001582 int fd;
Mika Kahola12e34d82016-11-23 11:19:37 +02001583
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001584 fd = igt_debugfs_open(device, "i915_display_info", O_RDONLY);
1585 file = fdopen(fd, "r");
1586 igt_skip_on(file == NULL);
Mika Kahola12e34d82016-11-23 11:19:37 +02001587
1588 ncrtc = 0;
1589 line = 0;
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001590 while (fgets(tmp, 256, file) != NULL) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001591 if ((strstr(tmp, "CRTC") != NULL) && (line > 0)) {
1592 if (strstr(tmp, "active=yes") != NULL) {
1593 crtc->active = true;
1594 parse_crtc(tmp, crtc);
Robert Foss9de63592017-01-18 12:12:54 -05001595
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001596 n = ftell(file);
1597 crtc->n_planes = parse_planes(file, NULL);
Petri Latvalabccb4a12019-01-16 13:20:40 +02001598 igt_assert_lt(0, crtc->n_planes);
Robert Foss260df252017-01-18 11:26:12 -05001599 crtc->planes = calloc(crtc->n_planes, sizeof(*crtc->planes));
1600 igt_assert_f(crtc->planes, "Failed to allocate memory for %d planes\n", crtc->n_planes);
1601
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001602 fseek(file, n, SEEK_SET);
1603 parse_planes(file, crtc->planes);
Mika Kahola12e34d82016-11-23 11:19:37 +02001604
Mika Kahola11e31f92017-02-16 11:20:45 +02001605 if (crtc->pipe != pipe) {
1606 free(crtc->planes);
1607 } else {
Mika Kahola12e34d82016-11-23 11:19:37 +02001608 ncrtc++;
Mika Kahola11e31f92017-02-16 11:20:45 +02001609 break;
1610 }
Mika Kahola12e34d82016-11-23 11:19:37 +02001611 }
1612 }
1613
1614 line++;
1615 }
1616
Chris Wilsone08ed8a2017-03-24 20:52:44 +00001617 fclose(file);
1618 close(fd);
Mika Kahola12e34d82016-11-23 11:19:37 +02001619
Maarten Lankhorstcdfe9922017-10-13 14:04:38 +02001620 igt_assert(ncrtc == 1);
Mika Kahola12e34d82016-11-23 11:19:37 +02001621}
1622
Carlos Santadf09cb52018-02-12 15:45:23 -08001623/**
1624 * igt_assert_plane_visible:
1625 * @fd: Opened file descriptor
1626 * @pipe: Display pipe
1627 * @visibility: Boolean parameter to test against the plane's current visibility state
1628 *
1629 * Asserts only if the plane's visibility state matches the status being passed by @visibility
1630 */
Chris Wilson83884e92017-03-21 17:16:03 +00001631void igt_assert_plane_visible(int fd, enum pipe pipe, bool visibility)
Mika Kahola12e34d82016-11-23 11:19:37 +02001632{
1633 struct kmstest_crtc crtc;
1634 int i;
1635 bool visible;
1636
Chris Wilson83884e92017-03-21 17:16:03 +00001637 kmstest_get_crtc(fd, pipe, &crtc);
Mika Kahola12e34d82016-11-23 11:19:37 +02001638
1639 visible = true;
Robert Foss260df252017-01-18 11:26:12 -05001640 for (i = 0; i < crtc.n_planes; i++) {
1641 if (crtc.planes[i].type == DRM_PLANE_TYPE_PRIMARY)
Robert Foss9de63592017-01-18 12:12:54 -05001642 continue;
1643
Robert Foss260df252017-01-18 11:26:12 -05001644 if (crtc.planes[i].pos_x > crtc.width) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001645 visible = false;
1646 break;
Robert Foss260df252017-01-18 11:26:12 -05001647 } else if (crtc.planes[i].pos_y > crtc.height) {
Mika Kahola12e34d82016-11-23 11:19:37 +02001648 visible = false;
1649 break;
1650 }
1651 }
1652
Maarten Lankhorstcdfe9922017-10-13 14:04:38 +02001653 free(crtc.planes);
Mika Kahola12e34d82016-11-23 11:19:37 +02001654 igt_assert_eq(visible, visibility);
1655}
1656
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001657/*
1658 * A small modeset API
1659 */
1660
1661#define LOG_SPACES " "
1662#define LOG_N_SPACES (sizeof(LOG_SPACES) - 1)
1663
1664#define LOG_INDENT(d, section) \
1665 do { \
1666 igt_display_log(d, "%s {\n", section); \
1667 igt_display_log_shift(d, 1); \
1668 } while (0)
1669#define LOG_UNINDENT(d) \
1670 do { \
1671 igt_display_log_shift(d, -1); \
1672 igt_display_log(d, "}\n"); \
1673 } while (0)
1674#define LOG(d, fmt, ...) igt_display_log(d, fmt, ## __VA_ARGS__)
1675
Daniel Vetterbd53d722014-03-13 17:27:47 +01001676static void __attribute__((format(printf, 2, 3)))
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001677igt_display_log(igt_display_t *display, const char *fmt, ...)
1678{
1679 va_list args;
Daniel Vetterbd53d722014-03-13 17:27:47 +01001680 int i;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001681
1682 va_start(args, fmt);
Daniel Vetterbd53d722014-03-13 17:27:47 +01001683 igt_debug("display: ");
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001684 for (i = 0; i < display->log_shift; i++)
Daniel Vetterbd53d722014-03-13 17:27:47 +01001685 igt_debug("%s", LOG_SPACES);
Thomas Wood8161a212014-12-02 10:54:54 +00001686 igt_vlog(IGT_LOG_DOMAIN, IGT_LOG_DEBUG, fmt, args);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001687 va_end(args);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001688}
1689
1690static void igt_display_log_shift(igt_display_t *display, int shift)
1691{
1692 display->log_shift += shift;
1693 igt_assert(display->log_shift >= 0);
1694}
1695
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01001696static void igt_output_refresh(igt_output_t *output)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001697{
1698 igt_display_t *display = output->display;
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02001699 unsigned long crtc_idx_mask = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001700
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02001701 if (output->pending_pipe != PIPE_NONE)
1702 crtc_idx_mask = 1 << output->pending_pipe;
Maarten Lankhorstd8518f32016-10-05 13:39:29 +02001703
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001704 kmstest_free_connector_config(&output->config);
Daniel Vetter1cad8342014-08-12 11:57:32 +02001705
Maarten Lankhorstba237f92017-01-10 10:50:50 +01001706 _kmstest_connector_config(display->drm_fd, output->id, crtc_idx_mask,
1707 &output->config, output->force_reprobe);
1708 output->force_reprobe = false;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001709
Maarten Lankhorst5a636682016-06-30 09:18:49 +02001710 if (!output->name && output->config.connector) {
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001711 drmModeConnector *c = output->config.connector;
1712
Thomas Wood47f6b132015-03-25 16:42:57 +00001713 igt_assert_neq(asprintf(&output->name, "%s-%d", kmstest_connector_type_str(c->connector_type), c->connector_type_id),
1714 -1);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001715 }
1716
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001717 if (output->config.connector)
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02001718 igt_atomic_fill_connector_props(display, output,
1719 IGT_NUM_CONNECTOR_PROPS, igt_connector_prop_names);
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02001720
Daniel Vetterdd8fba42014-08-12 11:00:37 +02001721 LOG(display, "%s: Selecting pipe %s\n", output->name,
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02001722 kmstest_pipe_name(output->pending_pipe));
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001723}
1724
Sonika Jindal7ef80c02015-04-07 13:59:03 +05301725static int
Damien Lespiau068efd82014-07-08 16:02:05 +01001726igt_plane_set_property(igt_plane_t *plane, uint32_t prop_id, uint64_t value)
1727{
1728 igt_pipe_t *pipe = plane->pipe;
1729 igt_display_t *display = pipe->display;
1730
Sonika Jindal7ef80c02015-04-07 13:59:03 +05301731 return drmModeObjectSetProperty(display->drm_fd, plane->drm_plane->plane_id,
Damien Lespiau068efd82014-07-08 16:02:05 +01001732 DRM_MODE_OBJECT_PLANE, prop_id, value);
1733}
1734
Matt Roper794a9fd2014-06-30 16:44:26 -07001735/*
1736 * Walk a plane's property list to determine its type. If we don't
1737 * find a type property, then the kernel doesn't support universal
1738 * planes and we know the plane is an overlay/sprite.
1739 */
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001740static int get_drm_plane_type(int drm_fd, uint32_t plane_id)
Matt Roper794a9fd2014-06-30 16:44:26 -07001741{
Damien Lespiau33842d52014-07-08 14:34:16 +01001742 uint64_t value;
1743 bool has_prop;
Matt Roper794a9fd2014-06-30 16:44:26 -07001744
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001745 has_prop = kmstest_get_property(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE,
1746 "type", NULL, &value, NULL);
Damien Lespiau33842d52014-07-08 14:34:16 +01001747 if (has_prop)
1748 return (int)value;
Matt Roper794a9fd2014-06-30 16:44:26 -07001749
Damien Lespiau33842d52014-07-08 14:34:16 +01001750 return DRM_PLANE_TYPE_OVERLAY;
Matt Roper794a9fd2014-06-30 16:44:26 -07001751}
1752
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001753static void igt_plane_reset(igt_plane_t *plane)
1754{
1755 /* Reset src coordinates. */
1756 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_X, 0);
1757 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_Y, 0);
1758 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_W, 0);
1759 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_H, 0);
1760
1761 /* Reset crtc coordinates. */
1762 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_X, 0);
1763 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_Y, 0);
1764 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_W, 0);
1765 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_H, 0);
1766
1767 /* Reset binding to fb and crtc. */
1768 igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, 0);
1769 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, 0);
1770
Ville Syrjäläa9a683e2018-03-06 20:01:44 +02001771 if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
Maarten Lankhorst903366f2018-06-08 15:04:13 +02001772 igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
1773 igt_color_encoding_to_str(IGT_COLOR_YCBCR_BT601));
1774
Ville Syrjäläa9a683e2018-03-06 20:01:44 +02001775 if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
Maarten Lankhorst903366f2018-06-08 15:04:13 +02001776 igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
1777 igt_color_range_to_str(IGT_COLOR_YCBCR_LIMITED_RANGE));
Ville Syrjäläa9a683e2018-03-06 20:01:44 +02001778
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001779 /* Use default rotation */
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01001780 if (igt_plane_has_prop(plane, IGT_PLANE_ROTATION))
1781 igt_plane_set_prop_value(plane, IGT_PLANE_ROTATION, IGT_ROTATION_0);
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001782
1783 igt_plane_clear_prop_changed(plane, IGT_PLANE_IN_FENCE_FD);
1784 plane->values[IGT_PLANE_IN_FENCE_FD] = ~0ULL;
Maarten Lankhorst84a130b2018-02-26 11:10:22 +01001785 plane->gem_handle = 0;
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001786}
1787
1788static void igt_pipe_reset(igt_pipe_t *pipe)
1789{
1790 igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, 0);
1791 igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_ACTIVE, 0);
1792 igt_pipe_obj_clear_prop_changed(pipe, IGT_CRTC_OUT_FENCE_PTR);
1793
1794 pipe->out_fence_fd = -1;
1795}
1796
1797static void igt_output_reset(igt_output_t *output)
1798{
1799 output->pending_pipe = PIPE_NONE;
1800 output->use_override_mode = false;
1801 memset(&output->override_mode, 0, sizeof(output->override_mode));
1802
1803 igt_output_set_prop_value(output, IGT_CONNECTOR_CRTC_ID, 0);
1804
1805 if (igt_output_has_prop(output, IGT_CONNECTOR_BROADCAST_RGB))
1806 igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB,
1807 BROADCAST_RGB_FULL);
1808}
1809
1810/**
1811 * igt_display_reset:
1812 * @display: a pointer to an #igt_display_t structure
1813 *
1814 * Reset basic pipes, connectors and planes on @display back to default values.
1815 * In particular, the following properties will be reset:
1816 *
1817 * For outputs:
1818 * - %IGT_CONNECTOR_CRTC_ID
1819 * - %IGT_CONNECTOR_BROADCAST_RGB (if applicable)
1820 * - igt_output_override_mode() to default.
1821 *
1822 * For pipes:
1823 * - %IGT_CRTC_MODE_ID (leaked)
1824 * - %IGT_CRTC_ACTIVE
1825 * - %IGT_CRTC_OUT_FENCE_PTR
1826 *
1827 * For planes:
1828 * - %IGT_PLANE_SRC_*
1829 * - %IGT_PLANE_CRTC_*
1830 * - %IGT_PLANE_FB_ID
1831 * - %IGT_PLANE_CRTC_ID
1832 * - %IGT_PLANE_ROTATION
1833 * - %IGT_PLANE_IN_FENCE_FD
1834 */
1835void igt_display_reset(igt_display_t *display)
1836{
1837 enum pipe pipe;
1838 int i;
1839
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01001840 /*
1841 * Allow resetting rotation on all planes, which is normally
1842 * prohibited on the primary and cursor plane for legacy commits.
1843 */
1844 display->first_commit = true;
1845
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001846 for_each_pipe(display, pipe) {
1847 igt_pipe_t *pipe_obj = &display->pipes[pipe];
1848 igt_plane_t *plane;
1849
1850 for_each_plane_on_pipe(display, pipe, plane)
1851 igt_plane_reset(plane);
1852
1853 igt_pipe_reset(pipe_obj);
1854 }
1855
1856 for (i = 0; i < display->n_outputs; i++) {
1857 igt_output_t *output = &display->outputs[i];
1858
1859 igt_output_reset(output);
1860 }
1861}
1862
Ville Syrjälä98f76142018-01-18 19:33:57 +02001863static void igt_fill_plane_format_mod(igt_display_t *display, igt_plane_t *plane);
1864static void igt_fill_display_format_mod(igt_display_t *display);
1865
Thomas Wood2e5a43d2015-11-02 15:48:52 +00001866/**
Daniel Vetter5105f062018-11-22 10:36:58 +01001867 * igt_display_require:
Thomas Wood2e5a43d2015-11-02 15:48:52 +00001868 * @display: a pointer to an #igt_display_t structure
1869 * @drm_fd: a drm file descriptor
1870 *
1871 * Initialize @display and allocate the various resources required. Use
1872 * #igt_display_fini to release the resources when they are no longer required.
1873 *
Daniel Vetter5105f062018-11-22 10:36:58 +01001874 * This function automatically skips if the kernel driver doesn't support any
1875 * CRTC or outputs.
Thomas Wood2e5a43d2015-11-02 15:48:52 +00001876 */
Daniel Vetter5105f062018-11-22 10:36:58 +01001877void igt_display_require(igt_display_t *display, int drm_fd)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001878{
1879 drmModeRes *resources;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001880 drmModePlaneRes *plane_resources;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001881 int i;
1882
Thomas Wood5874dad2014-06-16 16:12:21 +01001883 memset(display, 0, sizeof(igt_display_t));
1884
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001885 LOG_INDENT(display, "init");
1886
1887 display->drm_fd = drm_fd;
1888
1889 resources = drmModeGetResources(display->drm_fd);
Chris Wilson065e7dc2018-09-14 21:00:48 +01001890 if (!resources)
1891 goto out;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001892
1893 /*
1894 * We cache the number of pipes, that number is a physical limit of the
1895 * hardware and cannot change of time (for now, at least).
1896 */
1897 display->n_pipes = resources->count_crtcs;
Lyude3ccce992016-12-12 13:25:39 -05001898 display->pipes = calloc(sizeof(igt_pipe_t), display->n_pipes);
Robert Foss725edb32017-01-18 10:15:24 -05001899 igt_assert_f(display->pipes, "Failed to allocate memory for %d pipes\n", display->n_pipes);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001900
Matt Roper794a9fd2014-06-30 16:44:26 -07001901 drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02001902 if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) == 0)
1903 display->is_atomic = 1;
1904
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001905 plane_resources = drmModeGetPlaneResources(display->drm_fd);
1906 igt_assert(plane_resources);
1907
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01001908 for_each_pipe(display, i) {
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001909 igt_pipe_t *pipe = &display->pipes[i];
1910 igt_plane_t *plane;
Robert Foss36656232017-01-18 12:28:45 -05001911 int p = 1;
Matt Roper794a9fd2014-06-30 16:44:26 -07001912 int j, type;
Robert Foss36656232017-01-18 12:28:45 -05001913 uint8_t last_plane = 0, n_planes = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001914
Lionel Landwerlin59b54872016-03-18 17:33:00 +00001915 pipe->crtc_id = resources->crtcs[i];
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001916 pipe->display = display;
1917 pipe->pipe = i;
Robert Foss36656232017-01-18 12:28:45 -05001918 pipe->plane_cursor = -1;
1919 pipe->plane_primary = -1;
1920 pipe->planes = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001921
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02001922 igt_fill_pipe_props(display, pipe, IGT_NUM_CRTC_PROPS, igt_crtc_prop_names);
Maarten Lankhorsta8e23212016-07-25 15:14:54 +02001923
Robert Foss36656232017-01-18 12:28:45 -05001924 /* count number of valid planes */
1925 for (j = 0; j < plane_resources->count_planes; j++) {
1926 drmModePlane *drm_plane;
1927
1928 drm_plane = drmModeGetPlane(display->drm_fd,
1929 plane_resources->planes[j]);
1930 igt_assert(drm_plane);
1931
Brian Starkey4cb80db2017-02-20 11:02:44 +00001932 if (drm_plane->possible_crtcs & (1 << i))
1933 n_planes++;
Robert Foss36656232017-01-18 12:28:45 -05001934
Brian Starkey4cb80db2017-02-20 11:02:44 +00001935 drmModeFreePlane(drm_plane);
Robert Foss36656232017-01-18 12:28:45 -05001936 }
1937
Petri Latvala98c59bb2019-01-16 13:20:38 +02001938 igt_assert_lt(0, n_planes);
Robert Foss36656232017-01-18 12:28:45 -05001939 pipe->planes = calloc(sizeof(igt_plane_t), n_planes);
1940 igt_assert_f(pipe->planes, "Failed to allocate memory for %d planes\n", n_planes);
1941 last_plane = n_planes - 1;
1942
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001943 /* add the planes that can be used with that pipe */
1944 for (j = 0; j < plane_resources->count_planes; j++) {
1945 drmModePlane *drm_plane;
1946
1947 drm_plane = drmModeGetPlane(display->drm_fd,
1948 plane_resources->planes[j]);
1949 igt_assert(drm_plane);
1950
1951 if (!(drm_plane->possible_crtcs & (1 << i))) {
1952 drmModeFreePlane(drm_plane);
1953 continue;
1954 }
1955
Paulo Zanoni18d8ea72014-08-06 11:48:56 -03001956 type = get_drm_plane_type(display->drm_fd,
Matt Roper794a9fd2014-06-30 16:44:26 -07001957 plane_resources->planes[j]);
Brian Starkey1ab629f2017-02-20 11:02:45 +00001958
1959 if (type == DRM_PLANE_TYPE_PRIMARY && pipe->plane_primary == -1) {
1960 plane = &pipe->planes[0];
1961 plane->index = 0;
1962 pipe->plane_primary = 0;
1963 } else if (type == DRM_PLANE_TYPE_CURSOR && pipe->plane_cursor == -1) {
1964 plane = &pipe->planes[last_plane];
1965 plane->index = last_plane;
1966 pipe->plane_cursor = last_plane;
Lyude80baeb02016-12-07 19:02:04 -05001967 display->has_cursor_plane = true;
Brian Starkey1ab629f2017-02-20 11:02:45 +00001968 } else {
Matt Roper794a9fd2014-06-30 16:44:26 -07001969 plane = &pipe->planes[p];
1970 plane->index = p++;
Matt Roper794a9fd2014-06-30 16:44:26 -07001971 }
1972
Robert Foss36656232017-01-18 12:28:45 -05001973 igt_assert_f(plane->index < n_planes, "n_planes < plane->index failed\n");
1974 plane->type = type;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001975 plane->pipe = pipe;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001976 plane->drm_plane = drm_plane;
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02001977 plane->values[IGT_PLANE_IN_FENCE_FD] = ~0ULL;
Robert Foss235ff7a2016-05-18 20:07:04 -04001978
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02001979 igt_fill_plane_props(display, plane, IGT_NUM_PLANE_PROPS, igt_plane_prop_names);
Ville Syrjälä98f76142018-01-18 19:33:57 +02001980
1981 igt_fill_plane_format_mod(display, plane);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00001982 }
1983
Lyude80baeb02016-12-07 19:02:04 -05001984 /*
1985 * At the bare minimum, we should expect to have a primary
Brian Starkey45f9bb42017-02-20 11:02:46 +00001986 * plane, and it must be in slot 0.
Lyude80baeb02016-12-07 19:02:04 -05001987 */
Brian Starkey45f9bb42017-02-20 11:02:46 +00001988 igt_assert_eq(pipe->plane_primary, 0);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00001989
Brian Starkeybf2a1032017-06-05 14:28:37 +01001990 /* Check that we filled every slot exactly once */
1991 if (display->has_cursor_plane)
1992 igt_assert_eq(p, last_plane);
1993 else
1994 igt_assert_eq(p, n_planes);
Matt Roper794a9fd2014-06-30 16:44:26 -07001995
Robert Foss235ff7a2016-05-18 20:07:04 -04001996 pipe->n_planes = n_planes;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00001997 }
1998
Ville Syrjälä98f76142018-01-18 19:33:57 +02001999 igt_fill_display_format_mod(display);
2000
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002001 /*
2002 * The number of connectors is set, so we just initialize the outputs
2003 * array in _init(). This may change when we need dynamic connectors
2004 * (say DisplayPort MST).
2005 */
2006 display->n_outputs = resources->count_connectors;
2007 display->outputs = calloc(display->n_outputs, sizeof(igt_output_t));
Robert Foss725edb32017-01-18 10:15:24 -05002008 igt_assert_f(display->outputs, "Failed to allocate memory for %d outputs\n", display->n_outputs);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002009
2010 for (i = 0; i < display->n_outputs; i++) {
2011 igt_output_t *output = &display->outputs[i];
Maarten Lankhorst2c3e1ca2018-04-06 12:59:46 +02002012 drmModeConnector *connector;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002013
2014 /*
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002015 * We don't assign each output a pipe unless
2016 * a pipe is set with igt_output_set_pipe().
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002017 */
Maarten Lankhorst2cbd4dd2018-03-26 12:29:45 +02002018 output->pending_pipe = PIPE_NONE;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002019 output->id = resources->connectors[i];
2020 output->display = display;
2021
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002022 igt_output_refresh(output);
Maarten Lankhorst2cbd4dd2018-03-26 12:29:45 +02002023
Maarten Lankhorst2c3e1ca2018-04-06 12:59:46 +02002024 connector = output->config.connector;
2025 if (connector && (!connector->count_modes ||
2026 connector->connection == DRM_MODE_UNKNOWNCONNECTION)) {
Maarten Lankhorst2cbd4dd2018-03-26 12:29:45 +02002027 output->force_reprobe = true;
2028 igt_output_refresh(output);
2029 }
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002030 }
2031
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002032 drmModeFreePlaneResources(plane_resources);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002033 drmModeFreeResources(resources);
2034
Maarten Lankhorst7a5dbae2017-11-15 18:41:57 +01002035 /* Set reasonable default values for every object in the display. */
2036 igt_display_reset(display);
2037
Chris Wilson065e7dc2018-09-14 21:00:48 +01002038out:
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002039 LOG_UNINDENT(display);
Chris Wilson065e7dc2018-09-14 21:00:48 +01002040
Daniel Vetter4579ac12018-12-07 15:01:07 +01002041 if (display->n_pipes && display->n_outputs)
2042 igt_enable_connectors(drm_fd);
2043 else
2044 igt_skip("No KMS driver or no outputs, pipes: %d, outputs: %d\n",
2045 display->n_pipes, display->n_outputs);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002046}
2047
Carlos Santadf09cb52018-02-12 15:45:23 -08002048/**
2049 * igt_display_get_n_pipes:
2050 * @display: A pointer to an #igt_display_t structure
2051 *
2052 * Returns total number of pipes for the given @display
2053 */
Damien Lespiau72e9a6c2014-02-04 14:59:39 +00002054int igt_display_get_n_pipes(igt_display_t *display)
2055{
2056 return display->n_pipes;
2057}
2058
Carlos Santadf09cb52018-02-12 15:45:23 -08002059/**
2060 * igt_display_require_output:
2061 * @display: A pointer to an #igt_display_t structure
2062 *
2063 * Checks whether there's a valid @pipe/@output combination for the given @display
2064 * Skips test if a valid combination of @pipe and @output is not found
2065 */
Maarten Lankhorst0b8933d2017-06-12 11:03:22 +02002066void igt_display_require_output(igt_display_t *display)
2067{
2068 enum pipe pipe;
2069 igt_output_t *output;
2070
2071 for_each_pipe_with_valid_output(display, pipe, output)
2072 return;
2073
2074 igt_skip("No valid crtc/connector combinations found.\n");
2075}
2076
Carlos Santadf09cb52018-02-12 15:45:23 -08002077/**
2078 * igt_display_require_output_on_pipe:
2079 * @display: A pointer to an #igt_display_t structure
2080 * @pipe: Display pipe
2081 *
2082 * Checks whether there's a valid @pipe/@output combination for the given @display and @pipe
2083 * Skips test if a valid @pipe is not found
2084 */
Maarten Lankhorst0b8933d2017-06-12 11:03:22 +02002085void igt_display_require_output_on_pipe(igt_display_t *display, enum pipe pipe)
2086{
2087 igt_output_t *output;
2088
Gabriel Krisman Bertazi5763c892017-11-15 17:36:57 -02002089 igt_skip_on_f(pipe >= igt_display_get_n_pipes(display),
Maarten Lankhorst0b8933d2017-06-12 11:03:22 +02002090 "Pipe %s does not exist.\n", kmstest_pipe_name(pipe));
2091
2092 for_each_valid_output_on_pipe(display, pipe, output)
2093 return;
2094
2095 igt_skip("No valid connector found on pipe %s\n", kmstest_pipe_name(pipe));
2096}
2097
Lyude528cdaf2016-12-29 19:25:31 -05002098/**
2099 * igt_output_from_connector:
2100 * @display: a pointer to an #igt_display_t structure
2101 * @connector: a pointer to a drmModeConnector
2102 *
2103 * Finds the output corresponding to the given connector
2104 *
2105 * Returns: A #igt_output_t structure configured to use the connector, or NULL
2106 * if none was found
2107 */
2108igt_output_t *igt_output_from_connector(igt_display_t *display,
2109 drmModeConnector *connector)
2110{
2111 igt_output_t *output, *found = NULL;
Maarten Lankhorstb6252fc2017-11-16 10:07:06 +01002112 int i;
Lyude528cdaf2016-12-29 19:25:31 -05002113
Maarten Lankhorstb6252fc2017-11-16 10:07:06 +01002114 for (i = 0; i < display->n_outputs; i++) {
2115 output = &display->outputs[i];
2116
2117 if (output->config.connector &&
2118 output->config.connector->connector_id ==
Lyude528cdaf2016-12-29 19:25:31 -05002119 connector->connector_id) {
2120 found = output;
2121 break;
2122 }
2123 }
2124
2125 return found;
2126}
2127
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002128static void igt_pipe_fini(igt_pipe_t *pipe)
2129{
2130 int i;
2131
2132 for (i = 0; i < pipe->n_planes; i++) {
2133 igt_plane_t *plane = &pipe->planes[i];
2134
2135 if (plane->drm_plane) {
2136 drmModeFreePlane(plane->drm_plane);
2137 plane->drm_plane = NULL;
2138 }
2139 }
Robert Foss36656232017-01-18 12:28:45 -05002140
2141 free(pipe->planes);
2142 pipe->planes = NULL;
Maarten Lankhorst4258cc82017-07-06 07:47:47 +02002143
2144 if (pipe->out_fence_fd != -1)
2145 close(pipe->out_fence_fd);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002146}
2147
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002148static void igt_output_fini(igt_output_t *output)
2149{
Maarten Lankhorstba237f92017-01-10 10:50:50 +01002150 kmstest_free_connector_config(&output->config);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002151 free(output->name);
Robert Foss900f1d42017-01-16 10:53:58 -05002152 output->name = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002153}
2154
Thomas Wood2e5a43d2015-11-02 15:48:52 +00002155/**
2156 * igt_display_fini:
2157 * @display: a pointer to an #igt_display_t structure
2158 *
2159 * Release any resources associated with @display. This does not free @display
2160 * itself.
2161 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002162void igt_display_fini(igt_display_t *display)
2163{
2164 int i;
2165
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002166 for (i = 0; i < display->n_pipes; i++)
2167 igt_pipe_fini(&display->pipes[i]);
2168
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002169 for (i = 0; i < display->n_outputs; i++)
2170 igt_output_fini(&display->outputs[i]);
2171 free(display->outputs);
2172 display->outputs = NULL;
Robert Foss900f1d42017-01-16 10:53:58 -05002173 free(display->pipes);
2174 display->pipes = NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002175}
2176
2177static void igt_display_refresh(igt_display_t *display)
2178{
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002179 igt_output_t *output;
2180 int i;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002181
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002182 unsigned long pipes_in_use = 0;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002183
Damien Lespiau162914b2014-02-06 16:05:19 +00002184 /* Check that two outputs aren't trying to use the same pipe */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002185 for (i = 0; i < display->n_outputs; i++) {
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002186 output = &display->outputs[i];
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002187
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002188 if (output->pending_pipe != PIPE_NONE) {
2189 if (pipes_in_use & (1 << output->pending_pipe))
2190 goto report_dup;
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002191
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002192 pipes_in_use |= 1 << output->pending_pipe;
2193 }
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002194
2195 if (output->force_reprobe)
2196 igt_output_refresh(output);
2197 }
2198
2199 return;
2200
2201report_dup:
2202 for (; i > 0; i--) {
2203 igt_output_t *b = &display->outputs[i - 1];
2204
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002205 igt_assert_f(output->pending_pipe !=
2206 b->pending_pipe,
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01002207 "%s and %s are both trying to use pipe %s\n",
2208 igt_output_name(output), igt_output_name(b),
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002209 kmstest_pipe_name(output->pending_pipe));
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002210 }
2211}
2212
2213static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
2214{
2215 igt_display_t *display = output->display;
2216 enum pipe pipe;
2217
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002218 if (output->pending_pipe == PIPE_NONE) {
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002219 /*
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002220 * The user hasn't specified a pipe to use, return none.
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002221 */
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002222 return NULL;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002223 } else {
2224 /*
2225 * Otherwise, return the pending pipe (ie the pipe that should
2226 * drive this output after the commit()
2227 */
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002228 pipe = output->pending_pipe;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002229 }
2230
2231 igt_assert(pipe >= 0 && pipe < display->n_pipes);
2232
2233 return &display->pipes[pipe];
2234}
2235
Robert Foss36656232017-01-18 12:28:45 -05002236static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int plane_idx)
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002237{
Ville Syrjälä4ac32f42017-09-20 21:00:09 +03002238 igt_require_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2239 "Valid pipe->planes plane_idx not found, plane_idx=%d n_planes=%d",
2240 plane_idx, pipe->n_planes);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002241
Robert Foss36656232017-01-18 12:28:45 -05002242 return &pipe->planes[plane_idx];
2243}
2244
Carlos Santadf09cb52018-02-12 15:45:23 -08002245/**
2246 * igt_pipe_get_plane_type:
2247 * @pipe: Target pipe
2248 * @plane_type: Cursor, primary or an overlay plane
2249 *
2250 * Finds a valid plane type for the given @pipe otherwise
2251 * it skips the test if the right combination of @pipe/@plane_type is not found
2252 *
2253 * Returns: A #igt_plane_t structure that matches the requested plane type
2254 */
Robert Foss36656232017-01-18 12:28:45 -05002255igt_plane_t *igt_pipe_get_plane_type(igt_pipe_t *pipe, int plane_type)
2256{
2257 int i, plane_idx = -1;
2258
2259 switch(plane_type) {
2260 case DRM_PLANE_TYPE_CURSOR:
2261 plane_idx = pipe->plane_cursor;
2262 break;
2263 case DRM_PLANE_TYPE_PRIMARY:
2264 plane_idx = pipe->plane_primary;
2265 break;
2266 case DRM_PLANE_TYPE_OVERLAY:
2267 for(i = 0; i < pipe->n_planes; i++)
2268 if (pipe->planes[i].type == DRM_PLANE_TYPE_OVERLAY)
2269 plane_idx = i;
2270 break;
2271 default:
2272 break;
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002273 }
2274
Ville Syrjälä5426dc02017-09-07 19:00:55 +03002275 igt_require_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
2276 "Valid pipe->planes idx not found. plane_idx=%d plane_type=%d n_planes=%d\n",
2277 plane_idx, plane_type, pipe->n_planes);
Robert Foss36656232017-01-18 12:28:45 -05002278
2279 return &pipe->planes[plane_idx];
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002280}
2281
Maarten Lankhorst1ac64802018-02-21 11:17:25 +01002282static bool output_is_internal_panel(igt_output_t *output)
2283{
2284 switch (output->config.connector->connector_type) {
2285 case DRM_MODE_CONNECTOR_LVDS:
2286 case DRM_MODE_CONNECTOR_eDP:
2287 case DRM_MODE_CONNECTOR_DSI:
2288 case DRM_MODE_CONNECTOR_DPI:
2289 return true;
2290 default:
2291 return false;
2292 }
2293}
2294
2295igt_output_t **__igt_pipe_populate_outputs(igt_display_t *display, igt_output_t **chosen_outputs)
2296{
2297 unsigned full_pipe_mask = (1 << (display->n_pipes)) - 1, assigned_pipes = 0;
2298 igt_output_t *output;
2299 int i, j;
2300
2301 memset(chosen_outputs, 0, sizeof(*chosen_outputs) * display->n_pipes);
2302
2303 /*
2304 * Try to assign all outputs to the first available CRTC for
2305 * it, start with the outputs restricted to 1 pipe, then increase
2306 * number of pipes until we assign connectors to all pipes.
2307 */
2308 for (i = 0; i <= display->n_pipes; i++) {
2309 for_each_connected_output(display, output) {
2310 uint32_t pipe_mask = output->config.valid_crtc_idx_mask & full_pipe_mask;
2311 bool found = false;
2312
2313 if (output_is_internal_panel(output)) {
2314 /*
2315 * Internal panel should be assigned to pipe A
2316 * if possible, so make sure they're enumerated
2317 * first.
2318 */
2319
2320 if (i)
2321 continue;
2322 } else if (__builtin_popcount(pipe_mask) != i)
2323 continue;
2324
2325 for (j = 0; j < display->n_pipes; j++) {
2326 bool pipe_assigned = assigned_pipes & (1 << j);
2327
2328 if (pipe_assigned || !(pipe_mask & (1 << j)))
2329 continue;
2330
2331 if (!found) {
2332 /* We found an unassigned pipe, use it! */
2333 found = true;
2334 assigned_pipes |= 1 << j;
2335 chosen_outputs[j] = output;
2336 } else if (!chosen_outputs[j] ||
2337 /*
2338 * Overwrite internal panel if not assigned,
2339 * external outputs are faster to do modesets
2340 */
2341 output_is_internal_panel(chosen_outputs[j]))
2342 chosen_outputs[j] = output;
2343 }
2344
2345 if (!found)
2346 igt_warn("Output %s could not be assigned to a pipe\n",
2347 igt_output_name(output));
2348 }
2349 }
2350
2351 return chosen_outputs;
2352}
2353
2354/**
2355 * igt_get_single_output_for_pipe:
2356 * @display: a pointer to an #igt_display_t structure
2357 * @pipe: The pipe for which an #igt_output_t must be returned.
2358 *
2359 * Get a compatible output for a pipe.
2360 *
2361 * Returns: A compatible output for a given pipe, or NULL.
2362 */
2363igt_output_t *igt_get_single_output_for_pipe(igt_display_t *display, enum pipe pipe)
2364{
2365 igt_output_t *chosen_outputs[display->n_pipes];
2366
2367 igt_assert(pipe != PIPE_NONE);
2368 igt_require(pipe < display->n_pipes);
2369
2370 __igt_pipe_populate_outputs(display, chosen_outputs);
2371
2372 return chosen_outputs[pipe];
2373}
2374
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002375static igt_output_t *igt_pipe_get_output(igt_pipe_t *pipe)
2376{
2377 igt_display_t *display = pipe->display;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002378 int i;
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002379
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002380 for (i = 0; i < display->n_outputs; i++) {
2381 igt_output_t *output = &display->outputs[i];
2382
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02002383 if (output->pending_pipe == pipe->pipe)
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002384 return output;
Maarten Lankhorst5a636682016-06-30 09:18:49 +02002385 }
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002386
2387 return NULL;
2388}
2389
Damien Lespiaub4e85b72014-02-11 17:53:00 +00002390static uint32_t igt_plane_get_fb_id(igt_plane_t *plane)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002391{
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002392 return plane->values[IGT_PLANE_FB_ID];
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002393}
2394
Matt Roper82bc03f2014-06-30 16:44:25 -07002395#define CHECK_RETURN(r, fail) { \
2396 if (r && !fail) \
2397 return r; \
Tomeu Vizoso1e6fc782016-12-06 15:41:26 +01002398 igt_assert_eq(r, 0); \
Matt Roper82bc03f2014-06-30 16:44:25 -07002399}
2400
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302401/*
2402 * Add position and fb changes of a plane to the atomic property set
2403 */
2404static void
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002405igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302406 drmModeAtomicReq *req)
2407{
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002408 igt_display_t *display = pipe->display;
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002409 int i;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302410
2411 igt_assert(plane->drm_plane);
2412
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302413 LOG(display,
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02002414 "populating plane data: %s.%d, fb %u\n",
2415 kmstest_pipe_name(pipe->pipe),
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302416 plane->index,
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002417 igt_plane_get_fb_id(plane));
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302418
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002419 for (i = 0; i < IGT_NUM_PLANE_PROPS; i++) {
2420 if (!igt_plane_is_prop_changed(plane, i))
2421 continue;
2422
2423 /* it's an error to try an unsupported feature */
2424 igt_assert(plane->props[i]);
2425
2426 igt_debug("plane %s.%d: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
2427 kmstest_pipe_name(pipe->pipe), plane->index, igt_plane_prop_names[i],
2428 plane->values[i], plane->values[i]);
2429
2430 igt_assert_lt(0, drmModeAtomicAddProperty(req, plane->drm_plane->plane_id,
2431 plane->props[i],
2432 plane->values[i]));
Robert Foss221848d2016-06-20 10:24:08 -04002433 }
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302434}
2435
Maarten Lankhorst6e683662017-09-28 14:20:18 +02002436/*
2437 * Properties that can be changed through legacy SetProperty:
2438 * - Obviously not the XYWH SRC/CRTC coordinates.
2439 * - Not CRTC_ID or FENCE_ID, done through SetPlane.
2440 * - Can't set IN_FENCE_FD, that would be silly.
2441 *
2442 * Theoretically the above can all be set through the legacy path
2443 * with the atomic cap set, but that's not how our legacy plane
2444 * commit behaves, so blacklist it by default.
2445 */
2446#define LEGACY_PLANE_COMMIT_MASK \
2447 (((1ULL << IGT_NUM_PLANE_PROPS) - 1) & \
2448 ~(IGT_PLANE_COORD_CHANGED_MASK | \
2449 (1ULL << IGT_PLANE_FB_ID) | \
2450 (1ULL << IGT_PLANE_CRTC_ID) | \
2451 (1ULL << IGT_PLANE_IN_FENCE_FD)))
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05302452
Matt Roper82bc03f2014-06-30 16:44:25 -07002453/*
2454 * Commit position and fb changes to a DRM plane via the SetPlane ioctl; if the
2455 * DRM call to program the plane fails, we'll either fail immediately (for
2456 * tests that expect the commit to succeed) or return the failure code (for
2457 * tests that expect a specific error code).
2458 */
2459static int igt_drm_plane_commit(igt_plane_t *plane,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002460 igt_pipe_t *pipe,
Matt Roper82bc03f2014-06-30 16:44:25 -07002461 bool fail_on_error)
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002462{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002463 igt_display_t *display = pipe->display;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002464 uint32_t fb_id, crtc_id;
Maarten Lankhorst6e683662017-09-28 14:20:18 +02002465 int ret, i;
chandra kondurua26f9f92015-03-30 13:52:04 -07002466 uint32_t src_x;
2467 uint32_t src_y;
2468 uint32_t src_w;
2469 uint32_t src_h;
2470 int32_t crtc_x;
2471 int32_t crtc_y;
2472 uint32_t crtc_w;
2473 uint32_t crtc_h;
Maarten Lankhorst6e683662017-09-28 14:20:18 +02002474 uint64_t changed_mask;
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002475 bool setplane =
2476 igt_plane_is_prop_changed(plane, IGT_PLANE_FB_ID) ||
2477 plane->changed & IGT_PLANE_COORD_CHANGED_MASK;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002478
Matt Roper794a9fd2014-06-30 16:44:26 -07002479 igt_assert(plane->drm_plane);
2480
Damien Lespiaub4e85b72014-02-11 17:53:00 +00002481 fb_id = igt_plane_get_fb_id(plane);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002482 crtc_id = pipe->crtc_id;
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002483
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002484 if (setplane && fb_id == 0) {
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002485 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002486 "SetPlane pipe %s, plane %d, disabling\n",
2487 kmstest_pipe_name(pipe->pipe),
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002488 plane->index);
2489
2490 ret = drmModeSetPlane(display->drm_fd,
2491 plane->drm_plane->plane_id,
2492 crtc_id,
2493 fb_id,
2494 0, /* flags */
2495 0, 0, /* crtc_x, crtc_y */
2496 0, 0, /* crtc_w, crtc_h */
2497 IGT_FIXED(0,0), /* src_x */
2498 IGT_FIXED(0,0), /* src_y */
2499 IGT_FIXED(0,0), /* src_w */
2500 IGT_FIXED(0,0) /* src_h */);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002501
Matt Roper794a9fd2014-06-30 16:44:26 -07002502 CHECK_RETURN(ret, fail_on_error);
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002503 } else if (setplane) {
2504 src_x = plane->values[IGT_PLANE_SRC_X];
2505 src_y = plane->values[IGT_PLANE_SRC_Y];
2506 src_w = plane->values[IGT_PLANE_SRC_W];
2507 src_h = plane->values[IGT_PLANE_SRC_H];
2508 crtc_x = plane->values[IGT_PLANE_CRTC_X];
2509 crtc_y = plane->values[IGT_PLANE_CRTC_Y];
2510 crtc_w = plane->values[IGT_PLANE_CRTC_W];
2511 crtc_h = plane->values[IGT_PLANE_CRTC_H];
chandra kondurua26f9f92015-03-30 13:52:04 -07002512
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002513 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002514 "SetPlane %s.%d, fb %u, src = (%d, %d) "
chandra kondurua26f9f92015-03-30 13:52:04 -07002515 "%ux%u dst = (%u, %u) %ux%u\n",
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002516 kmstest_pipe_name(pipe->pipe),
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002517 plane->index,
2518 fb_id,
chandra kondurua26f9f92015-03-30 13:52:04 -07002519 src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
2520 crtc_x, crtc_y, crtc_w, crtc_h);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002521
2522 ret = drmModeSetPlane(display->drm_fd,
2523 plane->drm_plane->plane_id,
2524 crtc_id,
2525 fb_id,
2526 0, /* flags */
chandra kondurua26f9f92015-03-30 13:52:04 -07002527 crtc_x, crtc_y,
2528 crtc_w, crtc_h,
2529 src_x, src_y,
2530 src_w, src_h);
Matt Roper794a9fd2014-06-30 16:44:26 -07002531
Matt Roper82bc03f2014-06-30 16:44:25 -07002532 CHECK_RETURN(ret, fail_on_error);
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002533 }
2534
Maarten Lankhorst6e683662017-09-28 14:20:18 +02002535 changed_mask = plane->changed & LEGACY_PLANE_COMMIT_MASK;
2536
2537 for (i = 0; i < IGT_NUM_PLANE_PROPS; i++) {
2538 if (!(changed_mask & (1 << i)))
2539 continue;
2540
2541 LOG(display, "SetProp plane %s.%d \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
2542 kmstest_pipe_name(pipe->pipe), plane->index, igt_plane_prop_names[i],
2543 plane->values[i], plane->values[i]);
2544
2545 igt_assert(plane->props[i]);
2546
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002547 ret = igt_plane_set_property(plane,
Maarten Lankhorst6e683662017-09-28 14:20:18 +02002548 plane->props[i],
2549 plane->values[i]);
Damien Lespiau068efd82014-07-08 16:02:05 +01002550
Sonika Jindal7ef80c02015-04-07 13:59:03 +05302551 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau068efd82014-07-08 16:02:05 +01002552 }
2553
Damien Lespiauf0e0b2a2014-02-06 17:54:33 +00002554 return 0;
2555}
2556
Matt Roper794a9fd2014-06-30 16:44:26 -07002557/*
2558 * Commit position and fb changes to a cursor via legacy ioctl's. If commit
2559 * fails, we'll either fail immediately (for tests that expect the commit to
2560 * succeed) or return the failure code (for tests that expect a specific error
2561 * code).
2562 */
2563static int igt_cursor_commit_legacy(igt_plane_t *cursor,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002564 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002565 bool fail_on_error)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002566{
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002567 igt_display_t *display = pipe->display;
2568 uint32_t crtc_id = pipe->crtc_id;
Matt Roper794a9fd2014-06-30 16:44:26 -07002569 int ret;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002570
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002571 if (igt_plane_is_prop_changed(cursor, IGT_PLANE_FB_ID)) {
2572 if (cursor->gem_handle)
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002573 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002574 "SetCursor pipe %s, fb %u %dx%d\n",
2575 kmstest_pipe_name(pipe->pipe),
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002576 cursor->gem_handle,
2577 (unsigned)cursor->values[IGT_PLANE_CRTC_W],
2578 (unsigned)cursor->values[IGT_PLANE_CRTC_H]);
2579 else
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002580 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002581 "SetCursor pipe %s, disabling\n",
2582 kmstest_pipe_name(pipe->pipe));
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002583
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002584 ret = drmModeSetCursor(display->drm_fd, crtc_id,
2585 cursor->gem_handle,
2586 cursor->values[IGT_PLANE_CRTC_W],
2587 cursor->values[IGT_PLANE_CRTC_H]);
Matt Roper82bc03f2014-06-30 16:44:25 -07002588 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002589 }
2590
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002591 if (igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_X) ||
2592 igt_plane_is_prop_changed(cursor, IGT_PLANE_CRTC_Y)) {
2593 int x = cursor->values[IGT_PLANE_CRTC_X];
2594 int y = cursor->values[IGT_PLANE_CRTC_Y];
Matt Roper794a9fd2014-06-30 16:44:26 -07002595
2596 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002597 "MoveCursor pipe %s, (%d, %d)\n",
2598 kmstest_pipe_name(pipe->pipe),
Matt Roper794a9fd2014-06-30 16:44:26 -07002599 x, y);
2600
2601 ret = drmModeMoveCursor(display->drm_fd, crtc_id, x, y);
2602 CHECK_RETURN(ret, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002603 }
2604
2605 return 0;
2606}
2607
2608/*
2609 * Commit position and fb changes to a primary plane via the legacy interface
2610 * (setmode).
2611 */
2612static int igt_primary_plane_commit_legacy(igt_plane_t *primary,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002613 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002614 bool fail_on_error)
2615{
2616 struct igt_display *display = primary->pipe->display;
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002617 igt_output_t *output = igt_pipe_get_output(pipe);
Matt Roper794a9fd2014-06-30 16:44:26 -07002618 drmModeModeInfo *mode;
2619 uint32_t fb_id, crtc_id;
2620 int ret;
2621
2622 /* Primary planes can't be windowed when using a legacy commit */
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002623 igt_assert((primary->values[IGT_PLANE_CRTC_X] == 0 && primary->values[IGT_PLANE_CRTC_Y] == 0));
Matt Roper794a9fd2014-06-30 16:44:26 -07002624
Damien Lespiau068efd82014-07-08 16:02:05 +01002625 /* nor rotated */
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01002626 if (!pipe->display->first_commit)
2627 igt_assert(!igt_plane_is_prop_changed(primary, IGT_PLANE_ROTATION));
Damien Lespiau068efd82014-07-08 16:02:05 +01002628
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002629 if (!igt_plane_is_prop_changed(primary, IGT_PLANE_FB_ID) &&
2630 !(primary->changed & IGT_PLANE_COORD_CHANGED_MASK) &&
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02002631 !igt_pipe_obj_is_prop_changed(primary->pipe, IGT_CRTC_MODE_ID))
Matt Roper794a9fd2014-06-30 16:44:26 -07002632 return 0;
2633
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002634 crtc_id = pipe->crtc_id;
Maarten Lankhorst26d0da42017-10-03 16:11:42 +02002635 fb_id = output ? igt_plane_get_fb_id(primary) : 0;
Matt Roper794a9fd2014-06-30 16:44:26 -07002636 if (fb_id)
2637 mode = igt_output_get_mode(output);
2638 else
2639 mode = NULL;
2640
2641 if (fb_id) {
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002642 uint32_t src_x = primary->values[IGT_PLANE_SRC_X] >> 16;
2643 uint32_t src_y = primary->values[IGT_PLANE_SRC_Y] >> 16;
2644
Matt Roper794a9fd2014-06-30 16:44:26 -07002645 LOG(display,
Maarten Lankhorst0e29ce32016-06-30 11:32:10 +02002646 "%s: SetCrtc pipe %s, fb %u, src (%d, %d), "
Matt Roper794a9fd2014-06-30 16:44:26 -07002647 "mode %dx%d\n",
2648 igt_output_name(output),
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002649 kmstest_pipe_name(pipe->pipe),
Matt Roper794a9fd2014-06-30 16:44:26 -07002650 fb_id,
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002651 src_x, src_y,
Matt Roper794a9fd2014-06-30 16:44:26 -07002652 mode->hdisplay, mode->vdisplay);
2653
2654 ret = drmModeSetCrtc(display->drm_fd,
2655 crtc_id,
2656 fb_id,
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02002657 src_x, src_y,
Matt Roper794a9fd2014-06-30 16:44:26 -07002658 &output->id,
2659 1,
2660 mode);
2661 } else {
2662 LOG(display,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002663 "SetCrtc pipe %s, disabling\n",
2664 kmstest_pipe_name(pipe->pipe));
Matt Roper794a9fd2014-06-30 16:44:26 -07002665
2666 ret = drmModeSetCrtc(display->drm_fd,
2667 crtc_id,
2668 fb_id,
2669 0, 0, /* x, y */
2670 NULL, /* connectors */
2671 0, /* n_connectors */
2672 NULL /* mode */);
2673 }
2674
2675 CHECK_RETURN(ret, fail_on_error);
2676
Matt Roper794a9fd2014-06-30 16:44:26 -07002677 return 0;
2678}
2679
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01002680static int igt_plane_fixup_rotation(igt_plane_t *plane,
2681 igt_pipe_t *pipe)
2682{
2683 int ret;
2684
2685 if (!igt_plane_has_prop(plane, IGT_PLANE_ROTATION))
2686 return 0;
2687
2688 LOG(pipe->display, "Fixing up initial rotation pipe %s, plane %d\n",
2689 kmstest_pipe_name(pipe->pipe), plane->index);
2690
2691 /* First try the easy case, can we change rotation without problems? */
2692 ret = igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2693 plane->values[IGT_PLANE_ROTATION]);
2694 if (!ret)
2695 return 0;
2696
2697 /* Disable the plane, while we tinker with rotation */
2698 ret = drmModeSetPlane(pipe->display->drm_fd,
2699 plane->drm_plane->plane_id,
2700 pipe->crtc_id, 0, /* fb_id */
2701 0, /* flags */
2702 0, 0, 0, 0, /* crtc_x, crtc_y, crtc_w, crtc_h */
2703 IGT_FIXED(0,0), IGT_FIXED(0,0), /* src_x, src_y */
2704 IGT_FIXED(0,0), IGT_FIXED(0,0)); /* src_w, src_h */
2705
2706 if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY)
2707 return ret;
2708
2709 /* For primary plane, fall back to disabling the crtc. */
2710 if (ret) {
2711 ret = drmModeSetCrtc(pipe->display->drm_fd,
2712 pipe->crtc_id, 0, 0, 0, NULL, 0, NULL);
2713
2714 if (ret)
2715 return ret;
2716 }
2717
2718 /* and finally, set rotation property. */
2719 return igt_plane_set_property(plane, plane->props[IGT_PLANE_ROTATION],
2720 plane->values[IGT_PLANE_ROTATION]);
2721}
Matt Roper794a9fd2014-06-30 16:44:26 -07002722
2723/*
2724 * Commit position and fb changes to a plane. The value of @s will determine
2725 * which API is used to do the programming.
2726 */
2727static int igt_plane_commit(igt_plane_t *plane,
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002728 igt_pipe_t *pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002729 enum igt_commit_style s,
2730 bool fail_on_error)
2731{
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01002732 if (pipe->display->first_commit || (s == COMMIT_UNIVERSAL &&
2733 igt_plane_is_prop_changed(plane, IGT_PLANE_ROTATION))) {
2734 int ret;
2735
2736 ret = igt_plane_fixup_rotation(plane, pipe);
2737 CHECK_RETURN(ret, fail_on_error);
2738 }
2739
Robert Foss36656232017-01-18 12:28:45 -05002740 if (plane->type == DRM_PLANE_TYPE_CURSOR && s == COMMIT_LEGACY) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002741 return igt_cursor_commit_legacy(plane, pipe, fail_on_error);
Robert Foss36656232017-01-18 12:28:45 -05002742 } else if (plane->type == DRM_PLANE_TYPE_PRIMARY && s == COMMIT_LEGACY) {
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002743 return igt_primary_plane_commit_legacy(plane, pipe,
Matt Roper794a9fd2014-06-30 16:44:26 -07002744 fail_on_error);
2745 } else {
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02002746 return igt_drm_plane_commit(plane, pipe, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002747 }
2748}
2749
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02002750static bool is_atomic_prop(enum igt_atomic_crtc_properties prop)
2751{
2752 if (prop == IGT_CRTC_MODE_ID ||
2753 prop == IGT_CRTC_ACTIVE ||
2754 prop == IGT_CRTC_OUT_FENCE_PTR)
2755 return true;
2756
2757 return false;
2758}
2759
Matt Roper794a9fd2014-06-30 16:44:26 -07002760/*
2761 * Commit all plane changes to an output. Note that if @s is COMMIT_LEGACY,
2762 * enabling/disabling the primary plane will also enable/disable the CRTC.
2763 *
2764 * If @fail_on_error is true, any failure to commit plane state will lead
2765 * to subtest failure in the specific function where the failure occurs.
2766 * Otherwise, the first error code encountered will be returned and no
2767 * further programming will take place, which may result in some changes
2768 * taking effect and others not taking effect.
2769 */
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002770static int igt_pipe_commit(igt_pipe_t *pipe,
2771 enum igt_commit_style s,
2772 bool fail_on_error)
Matt Roper794a9fd2014-06-30 16:44:26 -07002773{
Matt Roper794a9fd2014-06-30 16:44:26 -07002774 int i;
2775 int ret;
Matt Roper794a9fd2014-06-30 16:44:26 -07002776
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02002777 for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
2778 if (igt_pipe_obj_is_prop_changed(pipe, i) &&
2779 !is_atomic_prop(i)) {
2780 igt_assert(pipe->props[i]);
chandra konduruace42082015-03-30 13:44:32 -07002781
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02002782 ret = drmModeObjectSetProperty(pipe->display->drm_fd,
2783 pipe->crtc_id, DRM_MODE_OBJECT_CRTC,
2784 pipe->props[i], pipe->values[i]);
2785
2786 CHECK_RETURN(ret, fail_on_error);
2787 }
Lionel Landwerlin17166252016-03-18 17:33:01 +00002788
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002789 for (i = 0; i < pipe->n_planes; i++) {
2790 igt_plane_t *plane = &pipe->planes[i];
2791
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02002792 ret = igt_plane_commit(plane, pipe, s, fail_on_error);
Matt Roper794a9fd2014-06-30 16:44:26 -07002793 CHECK_RETURN(ret, fail_on_error);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00002794 }
2795
Damien Lespiau3670d6d2014-01-27 16:25:43 +00002796 return 0;
2797}
2798
Maarten Lankhorstc0434282017-09-28 13:37:17 +02002799static int igt_output_commit(igt_output_t *output,
2800 enum igt_commit_style s,
2801 bool fail_on_error)
2802{
2803 int i, ret;
2804
2805 for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
2806 if (!igt_output_is_prop_changed(output, i))
2807 continue;
2808
2809 /* CRTC_ID is set by calling drmModeSetCrtc in the legacy path. */
2810 if (i == IGT_CONNECTOR_CRTC_ID)
2811 continue;
2812
2813 igt_assert(output->props[i]);
2814
2815 if (s == COMMIT_LEGACY)
2816 ret = drmModeConnectorSetProperty(output->display->drm_fd, output->id,
2817 output->props[i], output->values[i]);
2818 else
2819 ret = drmModeObjectSetProperty(output->display->drm_fd, output->id,
2820 DRM_MODE_OBJECT_CONNECTOR,
2821 output->props[i], output->values[i]);
2822
2823 CHECK_RETURN(ret, fail_on_error);
2824 }
2825
2826 return 0;
2827}
2828
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002829static uint64_t igt_mode_object_get_prop(igt_display_t *display,
2830 uint32_t object_type,
2831 uint32_t object_id,
2832 uint32_t prop)
2833{
2834 drmModeObjectPropertiesPtr proplist;
2835 bool found = false;
2836 int i;
2837 uint64_t ret;
2838
2839 proplist = drmModeObjectGetProperties(display->drm_fd, object_id, object_type);
2840 for (i = 0; i < proplist->count_props; i++) {
2841 if (proplist->props[i] != prop)
2842 continue;
2843
2844 found = true;
2845 break;
2846 }
2847
2848 igt_assert(found);
2849
2850 ret = proplist->prop_values[i];
2851
2852 drmModeFreeObjectProperties(proplist);
2853 return ret;
2854}
2855
2856/**
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01002857 * igt_plane_get_prop:
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002858 * @plane: Target plane.
2859 * @prop: Property to check.
2860 *
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01002861 * Return current value on a plane for a given property.
2862 *
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002863 * Returns: The value the property is set to, if this
2864 * is a blob, the blob id is returned. This can be passed
2865 * to drmModeGetPropertyBlob() to get the contents of the blob.
2866 */
2867uint64_t igt_plane_get_prop(igt_plane_t *plane, enum igt_atomic_plane_properties prop)
2868{
2869 igt_assert(igt_plane_has_prop(plane, prop));
2870
2871 return igt_mode_object_get_prop(plane->pipe->display, DRM_MODE_OBJECT_PLANE,
2872 plane->drm_plane->plane_id, plane->props[prop]);
2873}
2874
Maarten Lankhorst7beba5b2018-05-18 12:20:59 +02002875static bool igt_mode_object_get_prop_enum_value(int drm_fd, uint32_t id, const char *str, uint64_t *val)
2876{
2877 drmModePropertyPtr prop = drmModeGetProperty(drm_fd, id);
2878 int i;
2879
2880 igt_assert(id);
2881 igt_assert(prop);
2882
2883 for (i = 0; i < prop->count_enums; i++)
2884 if (!strcmp(str, prop->enums[i].name)) {
2885 *val = prop->enums[i].value;
2886 drmModeFreeProperty(prop);
2887 return true;
2888 }
2889
2890 return false;
2891}
2892
2893bool igt_plane_try_prop_enum(igt_plane_t *plane,
2894 enum igt_atomic_plane_properties prop,
2895 const char *val)
2896{
2897 igt_display_t *display = plane->pipe->display;
2898 uint64_t uval;
2899
2900 igt_assert(plane->props[prop]);
2901
2902 if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
2903 plane->props[prop], val, &uval))
2904 return false;
2905
2906 igt_plane_set_prop_value(plane, prop, uval);
2907 return true;
2908}
2909
2910void igt_plane_set_prop_enum(igt_plane_t *plane,
2911 enum igt_atomic_plane_properties prop,
2912 const char *val)
2913{
2914 igt_assert(igt_plane_try_prop_enum(plane, prop, val));
2915}
2916
Maarten Lankhorstcca28772017-10-03 09:38:07 +02002917/**
2918 * igt_plane_replace_prop_blob:
2919 * @plane: plane to set property on.
2920 * @prop: property for which the blob will be replaced.
2921 * @ptr: Pointer to contents for the property.
2922 * @length: Length of contents.
2923 *
2924 * This function will destroy the old property blob for the given property,
2925 * and will create a new property blob with the values passed to this function.
2926 *
2927 * The new property blob will be committed when you call igt_display_commit(),
2928 * igt_display_commit2() or igt_display_commit_atomic().
2929 */
2930void
2931igt_plane_replace_prop_blob(igt_plane_t *plane, enum igt_atomic_plane_properties prop, const void *ptr, size_t length)
2932{
2933 igt_display_t *display = plane->pipe->display;
2934 uint64_t *blob = &plane->values[prop];
2935 uint32_t blob_id = 0;
2936
2937 if (*blob != 0)
2938 igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
2939 *blob) == 0);
2940
2941 if (length > 0)
2942 igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
2943 ptr, length, &blob_id) == 0);
2944
2945 *blob = blob_id;
2946 igt_plane_set_prop_changed(plane, prop);
2947}
2948
2949/**
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01002950 * igt_output_get_prop:
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002951 * @output: Target output.
2952 * @prop: Property to return.
2953 *
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01002954 * Return current value on an output for a given property.
2955 *
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002956 * Returns: The value the property is set to, if this
2957 * is a blob, the blob id is returned. This can be passed
2958 * to drmModeGetPropertyBlob() to get the contents of the blob.
2959 */
2960uint64_t igt_output_get_prop(igt_output_t *output, enum igt_atomic_connector_properties prop)
2961{
2962 igt_assert(igt_output_has_prop(output, prop));
2963
2964 return igt_mode_object_get_prop(output->display, DRM_MODE_OBJECT_CONNECTOR,
2965 output->id, output->props[prop]);
2966}
2967
Maarten Lankhorst7beba5b2018-05-18 12:20:59 +02002968bool igt_output_try_prop_enum(igt_output_t *output,
2969 enum igt_atomic_connector_properties prop,
2970 const char *val)
2971{
2972 igt_display_t *display = output->display;
2973 uint64_t uval;
2974
2975 igt_assert(output->props[prop]);
2976
2977 if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
2978 output->props[prop], val, &uval))
2979 return false;
2980
2981 igt_output_set_prop_value(output, prop, uval);
2982 return true;
2983}
2984
2985void igt_output_set_prop_enum(igt_output_t *output,
2986 enum igt_atomic_connector_properties prop,
2987 const char *val)
2988{
2989 igt_assert(igt_output_try_prop_enum(output, prop, val));
2990}
2991
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02002992/**
Maarten Lankhorstcca28772017-10-03 09:38:07 +02002993 * igt_output_replace_prop_blob:
2994 * @output: output to set property on.
2995 * @prop: property for which the blob will be replaced.
2996 * @ptr: Pointer to contents for the property.
2997 * @length: Length of contents.
2998 *
2999 * This function will destroy the old property blob for the given property,
3000 * and will create a new property blob with the values passed to this function.
3001 *
3002 * The new property blob will be committed when you call igt_display_commit(),
3003 * igt_display_commit2() or igt_display_commit_atomic().
3004 */
3005void
3006igt_output_replace_prop_blob(igt_output_t *output, enum igt_atomic_connector_properties prop, const void *ptr, size_t length)
3007{
3008 igt_display_t *display = output->display;
3009 uint64_t *blob = &output->values[prop];
3010 uint32_t blob_id = 0;
3011
3012 if (*blob != 0)
3013 igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3014 *blob) == 0);
3015
3016 if (length > 0)
3017 igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3018 ptr, length, &blob_id) == 0);
3019
3020 *blob = blob_id;
3021 igt_output_set_prop_changed(output, prop);
3022}
3023
3024/**
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01003025 * igt_pipe_obj_get_prop:
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02003026 * @pipe: Target pipe.
3027 * @prop: Property to return.
3028 *
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01003029 * Return current value on a pipe for a given property.
3030 *
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02003031 * Returns: The value the property is set to, if this
3032 * is a blob, the blob id is returned. This can be passed
3033 * to drmModeGetPropertyBlob() to get the contents of the blob.
3034 */
3035uint64_t igt_pipe_obj_get_prop(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
3036{
3037 igt_assert(igt_pipe_obj_has_prop(pipe, prop));
3038
3039 return igt_mode_object_get_prop(pipe->display, DRM_MODE_OBJECT_CRTC,
3040 pipe->crtc_id, pipe->props[prop]);
3041}
3042
Maarten Lankhorst7beba5b2018-05-18 12:20:59 +02003043bool igt_pipe_obj_try_prop_enum(igt_pipe_t *pipe_obj,
3044 enum igt_atomic_crtc_properties prop,
3045 const char *val)
3046{
3047 igt_display_t *display = pipe_obj->display;
3048 uint64_t uval;
3049
3050 igt_assert(pipe_obj->props[prop]);
3051
3052 if (!igt_mode_object_get_prop_enum_value(display->drm_fd,
3053 pipe_obj->props[prop], val, &uval))
3054 return false;
3055
3056 igt_pipe_obj_set_prop_value(pipe_obj, prop, uval);
3057 return true;
3058}
3059
3060void igt_pipe_obj_set_prop_enum(igt_pipe_t *pipe_obj,
3061 enum igt_atomic_crtc_properties prop,
3062 const char *val)
3063{
3064 igt_assert(igt_pipe_obj_try_prop_enum(pipe_obj, prop, val));
3065}
3066
Maarten Lankhorst4ac36e62017-10-04 18:28:21 +02003067/**
Maarten Lankhorstcca28772017-10-03 09:38:07 +02003068 * igt_pipe_obj_replace_prop_blob:
3069 * @pipe: pipe to set property on.
3070 * @prop: property for which the blob will be replaced.
3071 * @ptr: Pointer to contents for the property.
3072 * @length: Length of contents.
3073 *
3074 * This function will destroy the old property blob for the given property,
3075 * and will create a new property blob with the values passed to this function.
3076 *
3077 * The new property blob will be committed when you call igt_display_commit(),
3078 * igt_display_commit2() or igt_display_commit_atomic().
3079 *
3080 * Please use igt_output_override_mode() if you want to set #IGT_CRTC_MODE_ID,
3081 * it works better with legacy commit.
3082 */
3083void
3084igt_pipe_obj_replace_prop_blob(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop, const void *ptr, size_t length)
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003085{
3086 igt_display_t *display = pipe->display;
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003087 uint64_t *blob = &pipe->values[prop];
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003088 uint32_t blob_id = 0;
3089
3090 if (*blob != 0)
3091 igt_assert(drmModeDestroyPropertyBlob(display->drm_fd,
3092 *blob) == 0);
3093
3094 if (length > 0)
3095 igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
3096 ptr, length, &blob_id) == 0);
3097
3098 *blob = blob_id;
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003099 igt_pipe_obj_set_prop_changed(pipe, prop);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003100}
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303101
3102/*
3103 * Add crtc property changes to the atomic property set
3104 */
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003105static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303106{
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003107 int i;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303108
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003109 for (i = 0; i < IGT_NUM_CRTC_PROPS; i++) {
3110 if (!igt_pipe_obj_is_prop_changed(pipe_obj, i))
3111 continue;
Lionel Landwerlin17166252016-03-18 17:33:01 +00003112
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003113 igt_debug("Pipe %s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3114 kmstest_pipe_name(pipe_obj->pipe), igt_crtc_prop_names[i],
3115 pipe_obj->values[i], pipe_obj->values[i]);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003116
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003117 igt_assert_lt(0, drmModeAtomicAddProperty(req, pipe_obj->crtc_id, pipe_obj->props[i], pipe_obj->values[i]));
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003118 }
3119
Maarten Lankhorst4258cc82017-07-06 07:47:47 +02003120 if (pipe_obj->out_fence_fd != -1) {
3121 close(pipe_obj->out_fence_fd);
3122 pipe_obj->out_fence_fd = -1;
3123 }
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303124}
3125
3126/*
3127 * Add connector property changes to the atomic property set
3128 */
3129static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
3130{
Maarten Lankhorst0404de42016-06-29 15:56:28 +02003131
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003132 int i;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303133
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003134 for (i = 0; i < IGT_NUM_CONNECTOR_PROPS; i++) {
3135 if (!igt_output_is_prop_changed(output, i))
3136 continue;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303137
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003138 /* it's an error to try an unsupported feature */
3139 igt_assert(output->props[i]);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003140
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003141 igt_debug("%s: Setting property \"%s\" to 0x%"PRIx64"/%"PRIi64"\n",
3142 igt_output_name(output), igt_connector_prop_names[i],
3143 output->values[i], output->values[i]);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003144
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003145 igt_assert_lt(0, drmModeAtomicAddProperty(req,
3146 output->config.connector->connector_id,
3147 output->props[i],
3148 output->values[i]));
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003149 }
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303150}
3151
3152/*
3153 * Commit all the changes of all the planes,crtcs, connectors
3154 * atomically using drmModeAtomicCommit()
3155 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003156static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_data)
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303157{
Maarten Lankhorst0404de42016-06-29 15:56:28 +02003158
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003159 int ret = 0, i;
3160 enum pipe pipe;
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303161 drmModeAtomicReq *req;
3162 igt_output_t *output;
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003163
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303164 if (display->is_atomic != 1)
3165 return -1;
3166 req = drmModeAtomicAlloc();
3167 drmModeAtomicSetCursor(req, 0);
3168
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003169 for_each_pipe(display, pipe) {
3170 igt_pipe_t *pipe_obj = &display->pipes[pipe];
Maarten Lankhorst4a185972016-06-28 14:28:20 +02003171 igt_plane_t *plane;
3172
3173 /*
3174 * Add CRTC Properties to the property set
3175 */
Maarten Lankhorstcf6b5a42017-10-16 15:34:53 +02003176 if (pipe_obj->changed)
3177 igt_atomic_prepare_crtc_commit(pipe_obj, req);
Maarten Lankhorst0404de42016-06-29 15:56:28 +02003178
3179 for_each_plane_on_pipe(display, pipe, plane) {
Maarten Lankhorstcf6b5a42017-10-16 15:34:53 +02003180 if (plane->changed)
3181 igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
Maarten Lankhorst0404de42016-06-29 15:56:28 +02003182 }
3183
Maarten Lankhorst4a185972016-06-28 14:28:20 +02003184 }
3185
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003186 for (i = 0; i < display->n_outputs; i++) {
3187 output = &display->outputs[i];
3188
Maarten Lankhorstcf6b5a42017-10-16 15:34:53 +02003189 if (!output->config.connector || !output->changed)
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003190 continue;
3191
3192 LOG(display, "%s: preparing atomic, pipe: %s\n",
3193 igt_output_name(output),
3194 kmstest_pipe_name(output->config.pipe));
3195
Maarten Lankhorst9f45ea12016-06-30 10:24:28 +02003196 igt_atomic_prepare_connector_commit(output, req);
3197 }
3198
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003199 ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data);
Robert Foss187ccf02017-01-31 11:43:35 -05003200
Mayuresh Gharpure0e2e8802016-03-11 13:55:29 +05303201 drmModeAtomicFree(req);
3202 return ret;
3203
3204}
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003205
3206static void
3207display_commit_changed(igt_display_t *display, enum igt_commit_style s)
Matt Roper82bc03f2014-06-30 16:44:25 -07003208{
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003209 int i;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003210 enum pipe pipe;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003211
3212 for_each_pipe(display, pipe) {
3213 igt_pipe_t *pipe_obj = &display->pipes[pipe];
3214 igt_plane_t *plane;
3215
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003216 if (s == COMMIT_ATOMIC) {
3217 if (igt_pipe_obj_is_prop_changed(pipe_obj, IGT_CRTC_OUT_FENCE_PTR))
3218 igt_assert(pipe_obj->out_fence_fd >= 0);
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003219
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003220 pipe_obj->values[IGT_CRTC_OUT_FENCE_PTR] = 0;
3221 pipe_obj->changed = 0;
3222 } else {
Maarten Lankhorst5ce2b9c2019-01-31 09:31:07 +01003223 for (i = 0; i < IGT_NUM_CRTC_PROPS; i++)
3224 if (!is_atomic_prop(i))
3225 igt_pipe_obj_clear_prop_changed(pipe_obj, i);
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003226
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003227 if (s != COMMIT_UNIVERSAL) {
3228 igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3229 igt_pipe_obj_clear_prop_changed(pipe_obj, IGT_CRTC_ACTIVE);
3230 }
Maarten Lankhorst2e6819c2017-07-05 14:01:02 +02003231 }
3232
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003233 for_each_plane_on_pipe(display, pipe, plane) {
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003234 if (s == COMMIT_ATOMIC) {
3235 int fd;
3236 plane->changed = 0;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003237
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003238 fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3239 if (fd != -1)
3240 close(fd);
Maarten Lankhorst2e6819c2017-07-05 14:01:02 +02003241
Maarten Lankhorst2e6819c2017-07-05 14:01:02 +02003242 /* reset fence_fd to prevent it from being set for the next commit */
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003243 plane->values[IGT_PLANE_IN_FENCE_FD] = -1;
3244 } else {
3245 plane->changed &= ~IGT_PLANE_COORD_CHANGED_MASK;
3246
3247 igt_plane_clear_prop_changed(plane, IGT_PLANE_CRTC_ID);
3248 igt_plane_clear_prop_changed(plane, IGT_PLANE_FB_ID);
3249
3250 if (s != COMMIT_LEGACY ||
3251 !(plane->type == DRM_PLANE_TYPE_PRIMARY ||
3252 plane->type == DRM_PLANE_TYPE_CURSOR))
Maarten Lankhorst6e683662017-09-28 14:20:18 +02003253 plane->changed &= ~LEGACY_PLANE_COMMIT_MASK;
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01003254
3255 if (display->first_commit)
3256 igt_plane_clear_prop_changed(plane, IGT_PLANE_ROTATION);
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003257 }
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003258 }
3259 }
3260
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003261 for (i = 0; i < display->n_outputs; i++) {
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003262 igt_output_t *output = &display->outputs[i];
3263
Maarten Lankhorstc0434282017-09-28 13:37:17 +02003264 if (s != COMMIT_UNIVERSAL)
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003265 output->changed = 0;
Maarten Lankhorstc0434282017-09-28 13:37:17 +02003266 else
3267 /* no modeset in universal commit, no change to crtc. */
3268 output->changed &= 1 << IGT_CONNECTOR_CRTC_ID;
Maarten Lankhorstb61dc532016-06-30 11:59:13 +02003269 }
Maarten Lankhorst42ee3f92017-11-16 16:57:31 +01003270
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003271 if (display->first_commit) {
Daniel Vetter4d0d81a2019-02-19 10:11:06 +01003272 igt_reset_fifo_underrun_reporting(display->drm_fd);
Maarten Lankhorstaed20302018-03-28 11:56:04 +02003273
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003274 igt_display_drop_events(display);
Daniel Vetter4d0d81a2019-02-19 10:11:06 +01003275
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003276 display->first_commit = false;
3277 }
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003278}
3279
3280/*
3281 * Commit all plane changes across all outputs of the display.
3282 *
3283 * If @fail_on_error is true, any failure to commit plane state will lead
3284 * to subtest failure in the specific function where the failure occurs.
3285 * Otherwise, the first error code encountered will be returned and no
3286 * further programming will take place, which may result in some changes
3287 * taking effect and others not taking effect.
3288 */
3289static int do_display_commit(igt_display_t *display,
3290 enum igt_commit_style s,
3291 bool fail_on_error)
3292{
Maarten Lankhorstc0434282017-09-28 13:37:17 +02003293 int i, ret = 0;
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003294 enum pipe pipe;
3295 LOG_INDENT(display, "commit");
3296
Daniel Vetter2af377e2018-11-22 10:36:59 +01003297 /* someone managed to bypass igt_display_require, catch them */
3298 assert(display->n_pipes && display->n_outputs);
Chris Wilson212b7132018-09-14 21:03:38 +01003299
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003300 igt_display_refresh(display);
3301
3302 if (s == COMMIT_ATOMIC) {
3303 ret = igt_atomic_commit(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003304 } else {
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003305 for_each_pipe(display, pipe) {
3306 igt_pipe_t *pipe_obj = &display->pipes[pipe];
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003307
3308 ret = igt_pipe_commit(pipe_obj, s, fail_on_error);
Maarten Lankhorst6311a192017-06-13 17:39:22 +02003309 if (ret)
3310 break;
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003311 }
3312
Maarten Lankhorstc0434282017-09-28 13:37:17 +02003313 for (i = 0; !ret && i < display->n_outputs; i++)
3314 ret = igt_output_commit(&display->outputs[i], s, fail_on_error);
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003315 }
3316
Maarten Lankhorst6311a192017-06-13 17:39:22 +02003317 LOG_UNINDENT(display);
3318 CHECK_RETURN(ret, fail_on_error);
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003319
3320 display_commit_changed(display, s);
Feceoru, Gabriel26bec972016-02-26 13:21:15 +02003321
Daniel Vetterc49542a2014-09-05 08:51:27 +02003322 igt_debug_wait_for_keypress("modeset");
Matt Roper82bc03f2014-06-30 16:44:25 -07003323
3324 return 0;
3325}
3326
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02003327/**
3328 * igt_display_try_commit_atomic:
3329 * @display: #igt_display_t to commit.
3330 * @flags: Flags passed to drmModeAtomicCommit.
3331 * @user_data: User defined pointer passed to drmModeAtomicCommit.
3332 *
3333 * This function is similar to #igt_display_try_commit2, but is
3334 * used when you want to pass different flags to the actual commit.
3335 *
3336 * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3337 * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3338 * or DRM_MODE_ATOMIC_TEST_ONLY.
3339 *
3340 * @user_data is returned in the event if you pass
3341 * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3342 *
3343 * This function will return an error if commit fails, instead of
3344 * aborting the test.
3345 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003346int igt_display_try_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3347{
3348 int ret;
3349
Daniel Vetter2af377e2018-11-22 10:36:59 +01003350 /* someone managed to bypass igt_display_require, catch them */
3351 assert(display->n_pipes && display->n_outputs);
Chris Wilson212b7132018-09-14 21:03:38 +01003352
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003353 LOG_INDENT(display, "commit");
3354
3355 igt_display_refresh(display);
3356
3357 ret = igt_atomic_commit(display, flags, user_data);
3358
3359 LOG_UNINDENT(display);
3360
3361 if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))
3362 return ret;
3363
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003364 if (display->first_commit)
3365 igt_fail_on_f(flags & (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK),
3366 "First commit has to drop all stale events\n");
3367
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003368 display_commit_changed(display, COMMIT_ATOMIC);
3369
3370 igt_debug_wait_for_keypress("modeset");
3371
3372 return 0;
3373}
3374
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02003375/**
3376 * igt_display_commit_atomic:
3377 * @display: #igt_display_t to commit.
3378 * @flags: Flags passed to drmModeAtomicCommit.
3379 * @user_data: User defined pointer passed to drmModeAtomicCommit.
3380 *
3381 * This function is similar to #igt_display_commit2, but is
3382 * used when you want to pass different flags to the actual commit.
3383 *
3384 * Useful flags can be DRM_MODE_ATOMIC_ALLOW_MODESET,
3385 * DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
3386 * or DRM_MODE_ATOMIC_TEST_ONLY.
3387 *
3388 * @user_data is returned in the event if you pass
3389 * DRM_MODE_PAGE_FLIP_EVENT to @flags.
3390 *
3391 * This function will abort the test if commit fails.
3392 */
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003393void igt_display_commit_atomic(igt_display_t *display, uint32_t flags, void *user_data)
3394{
3395 int ret = igt_display_try_commit_atomic(display, flags, user_data);
3396
3397 igt_assert_eq(ret, 0);
3398}
3399
Matt Roper1c255472014-06-30 16:44:24 -07003400/**
3401 * igt_display_commit2:
3402 * @display: DRM device handle
3403 * @s: Commit style
3404 *
3405 * Commits framebuffer and positioning changes to all planes of each display
3406 * pipe, using a specific API to perform the programming. This function should
3407 * be used to exercise a specific driver programming API; igt_display_commit
3408 * should be used instead if the API used is unimportant to the test being run.
3409 *
Matt Roper82bc03f2014-06-30 16:44:25 -07003410 * This function should only be used to commit changes that are expected to
3411 * succeed, since any failure during the commit process will cause the IGT
3412 * subtest to fail. To commit changes that are expected to fail, use
3413 * @igt_try_display_commit2 instead.
3414 *
Matt Roper1c255472014-06-30 16:44:24 -07003415 * Returns: 0 upon success. This function will never return upon failure
3416 * since igt_fail() at lower levels will longjmp out of it.
3417 */
3418int igt_display_commit2(igt_display_t *display,
3419 enum igt_commit_style s)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003420{
Matt Roper794a9fd2014-06-30 16:44:26 -07003421 do_display_commit(display, s, true);
3422
3423 return 0;
Matt Roper82bc03f2014-06-30 16:44:25 -07003424}
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003425
Matt Roper82bc03f2014-06-30 16:44:25 -07003426/**
3427 * igt_display_try_commit2:
3428 * @display: DRM device handle
3429 * @s: Commit style
3430 *
3431 * Attempts to commit framebuffer and positioning changes to all planes of each
3432 * display pipe. This function should be used to commit changes that are
3433 * expected to fail, so that the error code can be checked for correctness.
3434 * For changes that are expected to succeed, use @igt_display_commit instead.
3435 *
3436 * Note that in non-atomic commit styles, no display programming will be
3437 * performed after the first failure is encountered, so only some of the
3438 * operations requested by a test may have been completed. Tests that catch
3439 * errors returned by this function should take care to restore the display to
3440 * a sane state after a failure is detected.
3441 *
3442 * Returns: 0 upon success, otherwise the error code of the first error
3443 * encountered.
3444 */
3445int igt_display_try_commit2(igt_display_t *display, enum igt_commit_style s)
3446{
Matt Roper794a9fd2014-06-30 16:44:26 -07003447 return do_display_commit(display, s, false);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003448}
3449
Matt Roper1c255472014-06-30 16:44:24 -07003450/**
3451 * igt_display_commit:
3452 * @display: DRM device handle
Matt Roper1c255472014-06-30 16:44:24 -07003453 *
3454 * Commits framebuffer and positioning changes to all planes of each display
3455 * pipe.
3456 *
3457 * Returns: 0 upon success. This function will never return upon failure
3458 * since igt_fail() at lower levels will longjmp out of it.
3459 */
3460int igt_display_commit(igt_display_t *display)
3461{
3462 return igt_display_commit2(display, COMMIT_LEGACY);
3463}
3464
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003465/**
3466 * igt_display_drop_events:
3467 * @display: DRM device handle
3468 *
3469 * Nonblockingly reads all current events and drops them, for highest
3470 * reliablility, call igt_display_commit2() first to flush all outstanding
3471 * events.
3472 *
3473 * This will be called on the first commit after igt_display_reset() too,
3474 * to make sure any stale events are flushed.
3475 *
3476 * Returns: Number of dropped events.
3477 */
3478int igt_display_drop_events(igt_display_t *display)
3479{
3480 int ret = 0;
3481
3482 /* Clear all events from drm fd. */
3483 struct pollfd pfd = {
3484 .fd = display->drm_fd,
3485 .events = POLLIN
3486 };
3487
3488 while (poll(&pfd, 1, 0) > 0) {
Maarten Lankhorst64c21672018-02-15 12:47:09 +01003489 struct drm_event *ev;
3490 char buf[4096];
3491 ssize_t retval;
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003492
Maarten Lankhorst64c21672018-02-15 12:47:09 +01003493 retval = read(display->drm_fd, &buf, sizeof(buf));
3494 igt_assert_lt(0, retval);
3495
3496 for (int i = 0; i < retval; i += ev->length) {
3497 ev = (struct drm_event *)&buf[i];
3498
3499 igt_info("Dropping event type %u length %u\n", ev->type, ev->length);
3500 igt_assert(ev->length + i <= sizeof(buf));
3501 ret++;
3502 }
Maarten Lankhorst98c64b32017-12-07 09:21:36 +01003503 }
3504
3505 return ret;
3506}
3507
Carlos Santadf09cb52018-02-12 15:45:23 -08003508/**
3509 * igt_output_name:
3510 * @output: Target output
3511 *
3512 * Returns: String representing a connector's name, e.g. "DP-1".
3513 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003514const char *igt_output_name(igt_output_t *output)
3515{
3516 return output->name;
3517}
3518
Carlos Santadf09cb52018-02-12 15:45:23 -08003519/**
3520 * igt_output_get_mode:
3521 * @output: Target output
3522 *
3523 * Get the current mode of the given connector
3524 *
3525 * Returns: A #drmModeModeInfo struct representing the current mode
3526 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003527drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
3528{
Brian Starkeyc4d4d092017-06-16 15:00:06 +01003529 if (output->use_override_mode)
3530 return &output->override_mode;
3531 else
3532 return &output->config.default_mode;
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003533}
3534
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03003535/**
3536 * igt_output_override_mode:
Thomas Woodd01ebbd2015-06-29 16:47:14 +01003537 * @output: Output of which the mode will be overridden
Maarten Lankhorst11eeb472016-07-05 15:09:56 +02003538 * @mode: New mode, or NULL to disable override.
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03003539 *
3540 * Overrides the output's mode with @mode, so that it is used instead of the
3541 * mode obtained with get connectors. Note that the mode is used without
Thomas Woodd01ebbd2015-06-29 16:47:14 +01003542 * checking if the output supports it, so this might lead to unexpected results.
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03003543 */
3544void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode)
3545{
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003546 igt_pipe_t *pipe = igt_output_get_driving_pipe(output);
3547
Maarten Lankhorst11eeb472016-07-05 15:09:56 +02003548 if (mode)
3549 output->override_mode = *mode;
Maarten Lankhorst11eeb472016-07-05 15:09:56 +02003550
3551 output->use_override_mode = !!mode;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003552
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003553 if (pipe) {
3554 if (output->display->is_atomic)
Maarten Lankhorstcca28772017-10-03 09:38:07 +02003555 igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(*mode));
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003556 else
3557 igt_pipe_obj_set_prop_changed(pipe, IGT_CRTC_MODE_ID);
3558 }
Ander Conselvan de Oliveira9aeff2b2015-03-30 10:03:00 +03003559}
3560
Carlos Santadf09cb52018-02-12 15:45:23 -08003561/*
3562 * igt_output_set_pipe:
3563 * @output: Target output for which the pipe is being set to
3564 * @pipe: Display pipe to set to
3565 *
3566 * This function sets a @pipe to a specific @output connector by
3567 * setting the CRTC_ID property of the @pipe. The pipe
3568 * is only activated for all pipes except PIPE_NONE.
3569 */
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003570void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
3571{
3572 igt_display_t *display = output->display;
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003573 igt_pipe_t *old_pipe = NULL, *pipe_obj = NULL;;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003574
Maarten Lankhorstba237f92017-01-10 10:50:50 +01003575 igt_assert(output->name);
Chris Wilson1b17be52016-08-23 11:27:45 +01003576
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003577 if (output->pending_pipe != PIPE_NONE)
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003578 old_pipe = igt_output_get_driving_pipe(output);
3579
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003580 if (pipe != PIPE_NONE)
3581 pipe_obj = &display->pipes[pipe];
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003582
Maarten Lankhorst76c7a712017-09-27 12:25:37 +02003583 LOG(display, "%s: set_pipe(%s)\n", igt_output_name(output),
3584 kmstest_pipe_name(pipe));
3585 output->pending_pipe = pipe;
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003586
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003587 if (old_pipe) {
3588 igt_output_t *old_output;
3589
3590 old_output = igt_pipe_get_output(old_pipe);
3591 if (!old_output) {
3592 if (display->is_atomic)
Maarten Lankhorstcca28772017-10-03 09:38:07 +02003593 igt_pipe_obj_replace_prop_blob(old_pipe, IGT_CRTC_MODE_ID, NULL, 0);
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003594 else
3595 igt_pipe_obj_set_prop_changed(old_pipe, IGT_CRTC_MODE_ID);
3596
3597 igt_pipe_obj_set_prop_value(old_pipe, IGT_CRTC_ACTIVE, 0);
3598 }
3599 }
Maarten Lankhorstc7d4dab2016-06-30 12:33:47 +02003600
Maarten Lankhorst13ead622017-09-21 12:01:41 +02003601 igt_output_set_prop_value(output, IGT_CONNECTOR_CRTC_ID, pipe == PIPE_NONE ? 0 : display->pipes[pipe].crtc_id);
Maarten Lankhorstd8518f32016-10-05 13:39:29 +02003602
Maarten Lankhorst5635ea92017-03-20 18:40:10 +01003603 igt_output_refresh(output);
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003604
3605 if (pipe_obj) {
3606 if (display->is_atomic)
Maarten Lankhorstcca28772017-10-03 09:38:07 +02003607 igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003608 else
3609 igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
3610
3611 igt_pipe_obj_set_prop_value(pipe_obj, IGT_CRTC_ACTIVE, 1);
3612 }
3613}
3614
3615/*
3616 * igt_pipe_refresh:
3617 * @display: a pointer to an #igt_display_t structure
3618 * @pipe: Pipe to refresh
3619 * @force: Should be set to true if mode_blob is no longer considered
3620 * to be valid, for example after doing an atomic commit during fork or closing display fd.
3621 *
3622 * Requests the pipe to be part of the state on next update.
3623 * This is useful when state may have been out of sync after
3624 * a fork, or we just want to be sure the pipe is included
3625 * in the next commit.
3626 */
3627void igt_pipe_refresh(igt_display_t *display, enum pipe pipe, bool force)
3628{
3629 igt_pipe_t *pipe_obj = &display->pipes[pipe];
3630
3631 if (force && display->is_atomic) {
3632 igt_output_t *output = igt_pipe_get_output(pipe_obj);
3633
3634 pipe_obj->values[IGT_CRTC_MODE_ID] = 0;
3635 if (output)
Maarten Lankhorstcca28772017-10-03 09:38:07 +02003636 igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_MODE_ID, igt_output_get_mode(output), sizeof(drmModeModeInfo));
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003637 } else
3638 igt_pipe_obj_set_prop_changed(pipe_obj, IGT_CRTC_MODE_ID);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003639}
3640
Robert Foss36656232017-01-18 12:28:45 -05003641igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003642{
3643 igt_pipe_t *pipe;
3644
3645 pipe = igt_output_get_driving_pipe(output);
Maarten Lankhorste33c51e2016-07-25 15:24:29 +02003646 igt_assert(pipe);
3647
Robert Foss36656232017-01-18 12:28:45 -05003648 return igt_pipe_get_plane(pipe, plane_idx);
3649}
3650
Carlos Santadf09cb52018-02-12 15:45:23 -08003651/**
3652 * igt_output_get_plane_type:
3653 * @output: Target output
3654 * @plane_type: Cursor, primary or an overlay plane
3655 *
3656 * Finds a valid plane type for the given @output otherwise
3657 * the test is skipped if the right combination of @output/@plane_type is not found
3658 *
3659 * Returns: A #igt_plane_t structure that matches the requested plane type
3660 */
Robert Foss36656232017-01-18 12:28:45 -05003661igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type)
3662{
3663 igt_pipe_t *pipe;
3664
3665 pipe = igt_output_get_driving_pipe(output);
3666 igt_assert(pipe);
3667
3668 return igt_pipe_get_plane_type(pipe, plane_type);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003669}
3670
Carlos Santadf09cb52018-02-12 15:45:23 -08003671/**
3672 * igt_plane_set_fb:
3673 * @plane: Plane
3674 * @fb: Framebuffer pointer
3675 *
3676 * Pairs a given @framebuffer to a @plane
3677 *
3678 * This function also sets a default size and position for the framebuffer
3679 * to avoid crashes on applications that ignore to set these.
3680 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01003681void igt_plane_set_fb(igt_plane_t *plane, struct igt_fb *fb)
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003682{
3683 igt_pipe_t *pipe = plane->pipe;
3684 igt_display_t *display = pipe->display;
3685
Daniel Vetterdd8fba42014-08-12 11:00:37 +02003686 LOG(display, "%s.%d: plane_set_fb(%d)\n", kmstest_pipe_name(pipe->pipe),
Damien Lespiauda0f1cf2014-02-06 21:06:59 +00003687 plane->index, fb ? fb->fb_id : 0);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003688
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003689 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, fb ? pipe->crtc_id : 0);
3690 igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, fb ? fb->fb_id : 0);
3691
3692 if (plane->type == DRM_PLANE_TYPE_CURSOR && fb)
3693 plane->gem_handle = fb->gem_handle;
3694 else
3695 plane->gem_handle = 0;
3696
Ville Syrjälä7b767542014-09-12 20:18:04 +03003697 /* hack to keep tests working that don't call igt_plane_set_size() */
3698 if (fb) {
Tvrtko Ursulin980ccf12015-05-12 11:06:37 +01003699 /* set default plane size as fb size */
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003700 igt_plane_set_size(plane, fb->width, fb->height);
chandra kondurua26f9f92015-03-30 13:52:04 -07003701
3702 /* set default src pos/size as fb size */
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003703 igt_fb_set_position(fb, plane, 0, 0);
3704 igt_fb_set_size(fb, plane, fb->width, fb->height);
Ville Syrjäläa9a683e2018-03-06 20:01:44 +02003705
3706 if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
Maarten Lankhorst903366f2018-06-08 15:04:13 +02003707 igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
3708 igt_color_encoding_to_str(fb->color_encoding));
Ville Syrjäläa9a683e2018-03-06 20:01:44 +02003709 if (igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
Maarten Lankhorst903366f2018-06-08 15:04:13 +02003710 igt_plane_set_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
3711 igt_color_range_to_str(fb->color_range));
Tvrtko Ursulinc3bd6082015-05-12 11:06:36 +01003712 } else {
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003713 igt_plane_set_size(plane, 0, 0);
Maarten Lankhorst826150f2016-07-05 14:52:20 +02003714
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003715 /* set default src pos/size as fb size */
3716 igt_fb_set_position(fb, plane, 0, 0);
3717 igt_fb_set_size(fb, plane, 0, 0);
chandra kondurua26f9f92015-03-30 13:52:04 -07003718 }
Damien Lespiau5ec399b2014-02-05 16:36:51 +00003719}
3720
Robert Foss221848d2016-06-20 10:24:08 -04003721/**
3722 * igt_plane_set_fence_fd:
3723 * @plane: plane
3724 * @fence_fd: fence fd, disable fence_fd by setting it to -1
3725 *
3726 * This function sets a fence fd to enable a commit to wait for some event to
3727 * occur before completing.
3728 */
3729void igt_plane_set_fence_fd(igt_plane_t *plane, int fence_fd)
3730{
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003731 int64_t fd;
Robert Foss221848d2016-06-20 10:24:08 -04003732
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003733 fd = plane->values[IGT_PLANE_IN_FENCE_FD];
3734 if (fd != -1)
3735 close(fd);
3736
3737 if (fence_fd != -1) {
3738 fd = dup(fence_fd);
3739 igt_fail_on(fd == -1);
3740 } else
3741 fd = -1;
3742
3743 igt_plane_set_prop_value(plane, IGT_PLANE_IN_FENCE_FD, fd);
Robert Foss221848d2016-06-20 10:24:08 -04003744}
3745
Carlos Santadf09cb52018-02-12 15:45:23 -08003746/**
3747 * igt_plane_set_position:
3748 * @plane: Plane pointer for which position is to be set
3749 * @x: X coordinate
3750 * @y: Y coordinate
3751 *
3752 * This function sets a new (x,y) position for the given plane.
3753 * New position will be committed at plane commit time via drmModeSetPlane().
3754 */
Damien Lespiau5ec399b2014-02-05 16:36:51 +00003755void igt_plane_set_position(igt_plane_t *plane, int x, int y)
3756{
3757 igt_pipe_t *pipe = plane->pipe;
3758 igt_display_t *display = pipe->display;
3759
Daniel Vetterdd8fba42014-08-12 11:00:37 +02003760 LOG(display, "%s.%d: plane_set_position(%d,%d)\n",
3761 kmstest_pipe_name(pipe->pipe), plane->index, x, y);
Damien Lespiau5ec399b2014-02-05 16:36:51 +00003762
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003763 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_X, x);
3764 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_Y, y);
Damien Lespiau3670d6d2014-01-27 16:25:43 +00003765}
Daniel Vetter64401f52014-03-26 10:19:42 +01003766
chandra kondurua26f9f92015-03-30 13:52:04 -07003767/**
3768 * igt_plane_set_size:
3769 * @plane: plane pointer for which size to be set
3770 * @w: width
3771 * @h: height
3772 *
3773 * This function sets width and height for requested plane.
Thomas Woodd01ebbd2015-06-29 16:47:14 +01003774 * New size will be committed at plane commit time via
chandra kondurua26f9f92015-03-30 13:52:04 -07003775 * drmModeSetPlane().
3776 */
Ville Syrjälä7b767542014-09-12 20:18:04 +03003777void igt_plane_set_size(igt_plane_t *plane, int w, int h)
3778{
3779 igt_pipe_t *pipe = plane->pipe;
3780 igt_display_t *display = pipe->display;
3781
chandra kondurua26f9f92015-03-30 13:52:04 -07003782 LOG(display, "%s.%d: plane_set_size (%dx%d)\n",
Ville Syrjälä7b767542014-09-12 20:18:04 +03003783 kmstest_pipe_name(pipe->pipe), plane->index, w, h);
3784
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003785 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_W, w);
3786 igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_H, h);
chandra kondurua26f9f92015-03-30 13:52:04 -07003787}
3788
3789/**
3790 * igt_fb_set_position:
3791 * @fb: framebuffer pointer
Thomas Wood6141aa22015-05-14 16:00:25 +01003792 * @plane: plane
chandra kondurua26f9f92015-03-30 13:52:04 -07003793 * @x: X position
3794 * @y: Y position
3795 *
3796 * This function sets position for requested framebuffer as src to plane.
Thomas Wood6141aa22015-05-14 16:00:25 +01003797 * New position will be committed at plane commit time via drmModeSetPlane().
chandra kondurua26f9f92015-03-30 13:52:04 -07003798 */
3799void igt_fb_set_position(struct igt_fb *fb, igt_plane_t *plane,
3800 uint32_t x, uint32_t y)
3801{
3802 igt_pipe_t *pipe = plane->pipe;
3803 igt_display_t *display = pipe->display;
3804
3805 LOG(display, "%s.%d: fb_set_position(%d,%d)\n",
3806 kmstest_pipe_name(pipe->pipe), plane->index, x, y);
3807
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003808 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_X, IGT_FIXED(x, 0));
3809 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_Y, IGT_FIXED(y, 0));
chandra kondurua26f9f92015-03-30 13:52:04 -07003810}
3811
3812/**
Thomas Wood6141aa22015-05-14 16:00:25 +01003813 * igt_fb_set_size:
chandra kondurua26f9f92015-03-30 13:52:04 -07003814 * @fb: framebuffer pointer
Thomas Wood6141aa22015-05-14 16:00:25 +01003815 * @plane: plane
chandra kondurua26f9f92015-03-30 13:52:04 -07003816 * @w: width
3817 * @h: height
3818 *
3819 * This function sets fetch rect size from requested framebuffer as src
Thomas Wood6141aa22015-05-14 16:00:25 +01003820 * to plane. New size will be committed at plane commit time via
chandra kondurua26f9f92015-03-30 13:52:04 -07003821 * drmModeSetPlane().
3822 */
3823void igt_fb_set_size(struct igt_fb *fb, igt_plane_t *plane,
3824 uint32_t w, uint32_t h)
3825{
3826 igt_pipe_t *pipe = plane->pipe;
3827 igt_display_t *display = pipe->display;
3828
Ville Syrjälä0c028732016-02-12 21:15:07 +02003829 LOG(display, "%s.%d: fb_set_size(%dx%d)\n",
chandra kondurua26f9f92015-03-30 13:52:04 -07003830 kmstest_pipe_name(pipe->pipe), plane->index, w, h);
3831
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003832 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_W, IGT_FIXED(w, 0));
3833 igt_plane_set_prop_value(plane, IGT_PLANE_SRC_H, IGT_FIXED(h, 0));
Ville Syrjälä7b767542014-09-12 20:18:04 +03003834}
3835
Damien Lespiau068efd82014-07-08 16:02:05 +01003836static const char *rotation_name(igt_rotation_t rotation)
3837{
Joseph Garveyd242cd82017-11-22 15:05:55 -08003838 switch (rotation & IGT_ROTATION_MASK) {
Damien Lespiau068efd82014-07-08 16:02:05 +01003839 case IGT_ROTATION_0:
3840 return "0°";
3841 case IGT_ROTATION_90:
3842 return "90°";
3843 case IGT_ROTATION_180:
3844 return "180°";
3845 case IGT_ROTATION_270:
3846 return "270°";
3847 default:
3848 igt_assert(0);
3849 }
3850}
3851
Carlos Santadf09cb52018-02-12 15:45:23 -08003852/**
3853 * igt_plane_set_rotation:
3854 * @plane: Plane pointer for which rotation is to be set
3855 * @rotation: Plane rotation value (0, 90, 180, 270)
3856 *
3857 * This function sets a new rotation for the requested @plane.
3858 * New @rotation will be committed at plane commit time via
3859 * drmModeSetPlane().
3860 */
Damien Lespiau068efd82014-07-08 16:02:05 +01003861void igt_plane_set_rotation(igt_plane_t *plane, igt_rotation_t rotation)
3862{
3863 igt_pipe_t *pipe = plane->pipe;
3864 igt_display_t *display = pipe->display;
3865
Daniel Vetterdd8fba42014-08-12 11:00:37 +02003866 LOG(display, "%s.%d: plane_set_rotation(%s)\n",
3867 kmstest_pipe_name(pipe->pipe),
Damien Lespiau068efd82014-07-08 16:02:05 +01003868 plane->index, rotation_name(rotation));
3869
Maarten Lankhorst5e42c622017-09-21 14:30:09 +02003870 igt_plane_set_prop_value(plane, IGT_PLANE_ROTATION, rotation);
Damien Lespiau068efd82014-07-08 16:02:05 +01003871}
3872
Gustavo Padovan513846b2016-06-20 10:24:08 -04003873/**
3874 * igt_pipe_request_out_fence:
3875 * @pipe: pipe which out fence will be requested for
3876 *
3877 * Marks this pipe for requesting an out fence at the next atomic commit
3878 * will contain the fd number of the out fence created by KMS.
3879 */
3880void igt_pipe_request_out_fence(igt_pipe_t *pipe)
3881{
Maarten Lankhorst66fb4662017-09-21 16:07:48 +02003882 igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)&pipe->out_fence_fd);
Gustavo Padovan513846b2016-06-20 10:24:08 -04003883}
3884
Carlos Santadf09cb52018-02-12 15:45:23 -08003885/**
3886 * igt_wait_for_vblank_count:
3887 * @drm_fd: A drm file descriptor
3888 * @pipe: Pipe to wait_for_vblank on
3889 * @count: Number of vblanks to wait on
3890 *
3891 * Waits for a given number of vertical blank intervals
3892 */
Chris Wilson2c64f112017-03-13 15:58:26 +00003893void igt_wait_for_vblank_count(int drm_fd, enum pipe pipe, int count)
Daniel Vetter64401f52014-03-26 10:19:42 +01003894{
3895 drmVBlank wait_vbl;
Robert Foss8a4e62b2016-05-18 20:07:08 -04003896 uint32_t pipe_id_flag;
Daniel Vetter64401f52014-03-26 10:19:42 +01003897
3898 memset(&wait_vbl, 0, sizeof(wait_vbl));
Robert Foss8a4e62b2016-05-18 20:07:08 -04003899 pipe_id_flag = kmstest_get_vbl_flag(pipe);
Daniel Vetter64401f52014-03-26 10:19:42 +01003900
Robert Foss8a4e62b2016-05-18 20:07:08 -04003901 wait_vbl.request.type = DRM_VBLANK_RELATIVE;
3902 wait_vbl.request.type |= pipe_id_flag;
Chris Wilson2c64f112017-03-13 15:58:26 +00003903 wait_vbl.request.sequence = count;
Daniel Vetter64401f52014-03-26 10:19:42 +01003904
3905 igt_assert(drmWaitVBlank(drm_fd, &wait_vbl) == 0);
3906}
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003907
Carlos Santadf09cb52018-02-12 15:45:23 -08003908/**
3909 * igt_wait_for_vblank:
3910 * @drm_fd: A drm file descriptor
3911 * @pipe: Pipe to wait_for_vblank on
3912 *
3913 * Waits for 1 vertical blank intervals
3914 */
Chris Wilson2c64f112017-03-13 15:58:26 +00003915void igt_wait_for_vblank(int drm_fd, enum pipe pipe)
3916{
3917 igt_wait_for_vblank_count(drm_fd, pipe, 1);
3918}
3919
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003920/**
3921 * igt_enable_connectors:
3922 *
3923 * Force connectors to be enabled where this is known to work well. Use
3924 * #igt_reset_connectors to revert the changes.
3925 *
3926 * An exit handler is installed to ensure connectors are reset when the test
3927 * exits.
3928 */
Chris Wilsonc5c0dd22018-10-02 16:25:09 +01003929void igt_enable_connectors(int drm_fd)
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003930{
3931 drmModeRes *res;
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003932
3933 res = drmModeGetResources(drm_fd);
Chris Wilsonc5c0dd22018-10-02 16:25:09 +01003934 if (!res)
3935 return;
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003936
3937 for (int i = 0; i < res->count_connectors; i++) {
Chris Wilson53b52f42016-09-14 22:14:22 +01003938 drmModeConnector *c;
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003939
Chris Wilson53b52f42016-09-14 22:14:22 +01003940 /* Do a probe. This may be the first action after booting */
3941 c = drmModeGetConnector(drm_fd, res->connectors[i]);
Maarten Lankhorst3d7a27e2017-02-08 15:47:45 +01003942 if (!c) {
3943 igt_warn("Could not read connector %u: %m\n", res->connectors[i]);
3944 continue;
3945 }
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003946
3947 /* don't attempt to force connectors that are already connected
3948 */
3949 if (c->connection == DRM_MODE_CONNECTED)
3950 continue;
3951
3952 /* just enable VGA for now */
Thomas Woodbb484292014-07-28 16:01:27 +01003953 if (c->connector_type == DRM_MODE_CONNECTOR_VGA) {
3954 if (!kmstest_force_connector(drm_fd, c, FORCE_CONNECTOR_ON))
3955 igt_info("Unable to force state on %s-%d\n",
3956 kmstest_connector_type_str(c->connector_type),
3957 c->connector_type_id);
3958 }
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003959
3960 drmModeFreeConnector(c);
3961 }
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003962}
3963
3964/**
3965 * igt_reset_connectors:
3966 *
3967 * Remove any forced state from the connectors.
3968 */
3969void igt_reset_connectors(void)
3970{
Thomas Woodf675f672014-09-04 11:35:01 +01003971 /* reset the connectors stored in forced_connectors, avoiding any
3972 * functions that are not safe to call in signal handlers */
Chris Wilson0e11bef2016-05-26 15:06:30 +01003973 for (int i = 0; forced_connectors[i]; i++)
3974 igt_sysfs_set(forced_connectors_device[i],
3975 forced_connectors[i],
3976 "detect");
Thomas Woodb6ed9fb2014-05-28 14:06:01 +01003977}
Marius Vlad7ead45c2016-07-04 16:52:46 +03003978
Lyude6adb7b32016-11-17 10:06:09 -05003979/**
3980 * igt_watch_hotplug:
3981 *
3982 * Begin monitoring udev for sysfs hotplug events.
3983 *
3984 * Returns: a udev monitor for detecting hotplugs on
3985 */
3986struct udev_monitor *igt_watch_hotplug(void)
3987{
3988 struct udev *udev;
3989 struct udev_monitor *mon;
3990 int ret, flags, fd;
3991
3992 udev = udev_new();
3993 igt_assert(udev != NULL);
3994
3995 mon = udev_monitor_new_from_netlink(udev, "udev");
3996 igt_assert(mon != NULL);
3997
3998 ret = udev_monitor_filter_add_match_subsystem_devtype(mon,
3999 "drm",
4000 "drm_minor");
4001 igt_assert_eq(ret, 0);
4002 ret = udev_monitor_filter_update(mon);
4003 igt_assert_eq(ret, 0);
4004 ret = udev_monitor_enable_receiving(mon);
4005 igt_assert_eq(ret, 0);
4006
4007 /* Set the fd for udev as non blocking */
4008 fd = udev_monitor_get_fd(mon);
4009 flags = fcntl(fd, F_GETFL, 0);
4010 igt_assert(flags);
4011
4012 flags |= O_NONBLOCK;
4013 igt_assert_neq(fcntl(fd, F_SETFL, flags), -1);
4014
4015 return mon;
4016}
4017
Daniel Vetterd1e352d2019-02-20 22:17:39 +01004018static bool event_detected(struct udev_monitor *mon, int timeout_secs,
4019 const char *property)
Lyude6adb7b32016-11-17 10:06:09 -05004020{
4021 struct udev_device *dev;
4022 const char *hotplug_val;
4023 struct pollfd fd = {
4024 .fd = udev_monitor_get_fd(mon),
4025 .events = POLLIN
4026 };
4027 bool hotplug_received = false;
4028
4029 /* Go through all of the events pending on the udev monitor. Once we
4030 * receive a hotplug, we continue going through the rest of the events
4031 * so that redundant hotplug events don't change the results of future
4032 * checks
4033 */
4034 while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) {
4035 dev = udev_monitor_receive_device(mon);
4036
Daniel Vetterd1e352d2019-02-20 22:17:39 +01004037 hotplug_val = udev_device_get_property_value(dev, property);
Lyude6adb7b32016-11-17 10:06:09 -05004038 if (hotplug_val && atoi(hotplug_val) == 1)
4039 hotplug_received = true;
4040
4041 udev_device_unref(dev);
4042 }
4043
4044 return hotplug_received;
4045}
4046
4047/**
Daniel Vetterd1e352d2019-02-20 22:17:39 +01004048 * igt_hotplug_detected:
4049 * @mon: A udev monitor initialized with #igt_watch_hotplug
4050 * @timeout_secs: How long to wait for a hotplug event to occur.
4051 *
4052 * Assert that a hotplug event was received since we last checked the monitor.
4053 *
4054 * Returns: true if a sysfs hotplug event was received, false if we timed out
4055 */
4056bool igt_hotplug_detected(struct udev_monitor *mon, int timeout_secs)
4057{
4058 return event_detected(mon, timeout_secs, "HOTPLUG");
4059}
4060
4061/**
4062 * igt_lease_change_detected:
4063 * @mon: A udev monitor initialized with #igt_watch_hotplug
4064 * @timeout_secs: How long to wait for a lease change event to occur.
4065 *
4066 * Assert that a lease change event was received since we last checked the monitor.
4067 *
4068 * Returns: true if a sysfs lease change event was received, false if we timed out
4069 */
4070bool igt_lease_change_detected(struct udev_monitor *mon, int timeout_secs)
4071{
4072 return event_detected(mon, timeout_secs, "LEASE");
4073}
4074
4075/**
Lyude6adb7b32016-11-17 10:06:09 -05004076 * igt_flush_hotplugs:
4077 * @mon: A udev monitor initialized with #igt_watch_hotplug
4078 *
4079 * Get rid of any pending hotplug events
4080 */
4081void igt_flush_hotplugs(struct udev_monitor *mon)
4082{
4083 struct udev_device *dev;
4084
4085 while ((dev = udev_monitor_receive_device(mon)))
4086 udev_device_unref(dev);
4087}
4088
4089/**
4090 * igt_cleanup_hotplug:
Maarten Lankhorsta79c8502018-02-21 11:10:16 +01004091 * @mon: A udev monitor initialized with #igt_watch_hotplug
Lyude6adb7b32016-11-17 10:06:09 -05004092 *
4093 * Cleanup the resources allocated by #igt_watch_hotplug
4094 */
4095void igt_cleanup_hotplug(struct udev_monitor *mon)
4096{
4097 struct udev *udev = udev_monitor_get_udev(mon);
4098
4099 udev_monitor_unref(mon);
4100 mon = NULL;
4101 udev_unref(udev);
4102}
Lyude6adb7b32016-11-17 10:06:09 -05004103
Marius Vlad7ead45c2016-07-04 16:52:46 +03004104/**
4105 * kmstest_get_vbl_flag:
Maarten Lankhorst2d672a12016-07-27 15:33:12 +02004106 * @pipe_id: Pipe to convert to flag representation.
Marius Vlad7ead45c2016-07-04 16:52:46 +03004107 *
4108 * Convert a pipe id into the flag representation
4109 * expected in DRM while processing DRM_IOCTL_WAIT_VBLANK.
4110 */
4111uint32_t kmstest_get_vbl_flag(uint32_t pipe_id)
4112{
4113 if (pipe_id == 0)
4114 return 0;
4115 else if (pipe_id == 1)
4116 return _DRM_VBLANK_SECONDARY;
4117 else {
4118 uint32_t pipe_flag = pipe_id << 1;
4119 igt_assert(!(pipe_flag & ~DRM_VBLANK_HIGH_CRTC_MASK));
4120 return pipe_flag;
4121 }
4122}
Ville Syrjälä98f76142018-01-18 19:33:57 +02004123
4124static inline const uint32_t *
4125formats_ptr(const struct drm_format_modifier_blob *blob)
4126{
4127 return (const uint32_t *)((const char *)blob + blob->formats_offset);
4128}
4129
4130static inline const struct drm_format_modifier *
4131modifiers_ptr(const struct drm_format_modifier_blob *blob)
4132{
4133 return (const struct drm_format_modifier *)((const char *)blob + blob->modifiers_offset);
4134}
4135
4136static int igt_count_plane_format_mod(const struct drm_format_modifier_blob *blob_data)
4137{
4138 const struct drm_format_modifier *modifiers;
4139 int count = 0;
4140
4141 modifiers = modifiers_ptr(blob_data);
4142
4143 for (int i = 0; i < blob_data->count_modifiers; i++)
4144 count += igt_hweight(modifiers[i].formats);
4145
4146 return count;
4147}
4148
4149static void igt_fill_plane_format_mod(igt_display_t *display, igt_plane_t *plane)
4150{
4151 const struct drm_format_modifier_blob *blob_data;
4152 drmModePropertyBlobPtr blob;
4153 uint64_t blob_id;
4154 int idx = 0;
4155 int count;
4156
Ville Syrjäläb05c0282018-03-16 19:11:59 +02004157 if (!igt_plane_has_prop(plane, IGT_PLANE_IN_FORMATS)) {
4158 drmModePlanePtr p = plane->drm_plane;
4159
4160 count = p->count_formats;
4161
4162 plane->format_mod_count = count;
4163 plane->formats = calloc(count, sizeof(plane->formats[0]));
4164 igt_assert(plane->formats);
4165 plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4166 igt_assert(plane->modifiers);
4167
4168 /*
4169 * We don't know which modifiers are
4170 * supported, so we'll assume linear only.
4171 */
4172 for (int i = 0; i < count; i++) {
4173 plane->formats[i] = p->formats[i];
4174 plane->modifiers[i] = DRM_FORMAT_MOD_LINEAR;
4175 }
4176
Daniel Stoneddc4ffb2018-03-21 11:07:28 +00004177 return;
Ville Syrjäläb05c0282018-03-16 19:11:59 +02004178 }
Daniel Stoneddc4ffb2018-03-21 11:07:28 +00004179
Ville Syrjälä98f76142018-01-18 19:33:57 +02004180 blob_id = igt_plane_get_prop(plane, IGT_PLANE_IN_FORMATS);
4181
4182 blob = drmModeGetPropertyBlob(display->drm_fd, blob_id);
4183 if (!blob)
4184 return;
4185
4186 blob_data = (const struct drm_format_modifier_blob *) blob->data;
4187
4188 count = igt_count_plane_format_mod(blob_data);
4189 if (!count)
4190 return;
4191
4192 plane->format_mod_count = count;
4193 plane->formats = calloc(count, sizeof(plane->formats[0]));
4194 igt_assert(plane->formats);
4195 plane->modifiers = calloc(count, sizeof(plane->modifiers[0]));
4196 igt_assert(plane->modifiers);
4197
4198 for (int i = 0; i < blob_data->count_modifiers; i++) {
4199 for (int j = 0; j < 64; j++) {
4200 const struct drm_format_modifier *modifiers =
4201 modifiers_ptr(blob_data);
4202 const uint32_t *formats = formats_ptr(blob_data);
4203
4204 if (!(modifiers[i].formats & (1ULL << j)))
4205 continue;
4206
4207 plane->formats[idx] = formats[modifiers[i].offset + j];
4208 plane->modifiers[idx] = modifiers[i].modifier;
4209 idx++;
4210 igt_assert_lte(idx, plane->format_mod_count);
4211 }
4212 }
4213
4214 igt_assert_eq(idx, plane->format_mod_count);
4215}
4216
4217bool igt_plane_has_format_mod(igt_plane_t *plane, uint32_t format,
4218 uint64_t modifier)
4219{
4220 int i;
4221
4222 for (i = 0; i < plane->format_mod_count; i++) {
4223 if (plane->formats[i] == format &&
4224 plane->modifiers[i] == modifier)
4225 return true;
4226
4227 }
4228
4229 return false;
4230}
4231
4232static int igt_count_display_format_mod(igt_display_t *display)
4233{
4234 enum pipe pipe;
4235 int count = 0;
4236
4237 for_each_pipe(display, pipe) {
4238 igt_plane_t *plane;
4239
4240 for_each_plane_on_pipe(display, pipe, plane) {
4241 count += plane->format_mod_count;
4242 }
4243 }
4244
4245 return count;
4246}
4247
4248static void
4249igt_add_display_format_mod(igt_display_t *display, uint32_t format,
4250 uint64_t modifier)
4251{
4252 int i;
4253
4254 for (i = 0; i < display->format_mod_count; i++) {
4255 if (display->formats[i] == format &&
4256 display->modifiers[i] == modifier)
4257 return;
4258
4259 }
4260
4261 display->formats[i] = format;
4262 display->modifiers[i] = modifier;
4263 display->format_mod_count++;
4264}
4265
4266static void igt_fill_display_format_mod(igt_display_t *display)
4267{
4268 int count = igt_count_display_format_mod(display);
4269 enum pipe pipe;
4270
4271 if (!count)
4272 return;
4273
4274 display->formats = calloc(count, sizeof(display->formats[0]));
4275 igt_assert(display->formats);
4276 display->modifiers = calloc(count, sizeof(display->modifiers[0]));
4277 igt_assert(display->modifiers);
4278
4279 for_each_pipe(display, pipe) {
4280 igt_plane_t *plane;
4281
4282 for_each_plane_on_pipe(display, pipe, plane) {
4283 for (int i = 0; i < plane->format_mod_count; i++) {
4284 igt_add_display_format_mod(display,
4285 plane->formats[i],
4286 plane->modifiers[i]);
4287 igt_assert_lte(display->format_mod_count, count);
4288 }
4289 }
4290 }
4291}
4292
4293bool igt_display_has_format_mod(igt_display_t *display, uint32_t format,
4294 uint64_t modifier)
4295{
4296 int i;
4297
4298 for (i = 0; i < display->format_mod_count; i++) {
4299 if (display->formats[i] == format &&
4300 display->modifiers[i] == modifier)
4301 return true;
4302
4303 }
4304
4305 return false;
4306}