blob: 62d933272423afc1d056f25c59c941870e0339c4 [file] [log] [blame]
Jesse Barnes731cd552008-12-17 10:09:49 -08001/*
2 * DRM based mode setting test program
3 * Copyright 2008 Tungsten Graphics
4 * Jakob Bornecrantz <jakob@tungstengraphics.com>
5 * Copyright 2008 Intel Corporation
6 * Jesse Barnes <jesse.barnes@intel.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26
27/*
28 * This fairly simple test program dumps output in a similar format to the
29 * "xrandr" tool everyone knows & loves. It's necessarily slightly different
30 * since the kernel separates outputs into encoder and connector structures,
31 * each with their own unique ID. The program also allows test testing of the
32 * memory management and mode setting APIs by allowing the user to specify a
33 * connector and mode to use for mode setting. If all works as expected, a
34 * blue background should be painted on the monitor attached to the specified
35 * connector after the selected mode is set.
36 *
37 * TODO: use cairo to write the mode info on the selected output once
38 * the mode has been programmed, along with possible test patterns.
39 */
Thierry Reding1ec3c442015-12-09 18:37:39 +010040
Emil Velikov8e93afc2014-07-27 14:46:45 +010041#ifdef HAVE_CONFIG_H
Kristian Høgsberg7a389aa2009-02-03 15:03:41 -050042#include "config.h"
Emil Velikov8e93afc2014-07-27 14:46:45 +010043#endif
Kristian Høgsberg7a389aa2009-02-03 15:03:41 -050044
Jesse Barnes731cd552008-12-17 10:09:49 -080045#include <assert.h>
Laurent Pinchart2c5ee842013-03-19 13:48:36 +010046#include <ctype.h>
Laurent Pinchart7badcca2013-02-27 05:35:13 +010047#include <stdbool.h>
Jesse Barnes731cd552008-12-17 10:09:49 -080048#include <stdio.h>
49#include <stdlib.h>
50#include <stdint.h>
Paulo Zanonid72a44c2012-04-21 17:51:53 -030051#include <inttypes.h>
Jesse Barnes731cd552008-12-17 10:09:49 -080052#include <unistd.h>
53#include <string.h>
Greg Hackmann0c8db0a2015-04-16 10:55:40 -070054#include <strings.h>
Jesse Barnes731cd552008-12-17 10:09:49 -080055#include <errno.h>
Kylie McClainff0c9ca2016-01-19 22:27:28 -050056#include <poll.h>
Matthew W. S. Belle4a51962010-01-30 02:14:44 +000057#include <sys/time.h>
Khem Raj358615f2016-01-20 05:35:11 +000058#ifdef HAVE_SYS_SELECT_H
59#include <sys/select.h>
60#endif
Jesse Barnes731cd552008-12-17 10:09:49 -080061
62#include "xf86drm.h"
63#include "xf86drmMode.h"
Rob Clarkd55de742011-12-14 21:06:43 -060064#include "drm_fourcc.h"
Jesse Barnes731cd552008-12-17 10:09:49 -080065
Thierry Reding1ec3c442015-12-09 18:37:39 +010066#include "util/common.h"
67#include "util/format.h"
Thierry Reding4664d652015-12-09 18:37:40 +010068#include "util/kms.h"
Thierry Reding1ec3c442015-12-09 18:37:39 +010069#include "util/pattern.h"
70
Laurent Pinchartdb004ba2012-07-20 16:37:00 +020071#include "buffers.h"
Rob Clark0e512792014-04-22 10:33:12 -040072#include "cursor.h"
Kristian Høgsberg7a389aa2009-02-03 15:03:41 -050073
Laurent Pinchart02fa8f72013-02-27 06:39:36 +010074struct crtc {
75 drmModeCrtc *crtc;
76 drmModeObjectProperties *props;
77 drmModePropertyRes **props_info;
Laurent Pinchart56592682013-02-27 05:35:13 +010078 drmModeModeInfo *mode;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +010079};
80
81struct encoder {
82 drmModeEncoder *encoder;
83};
84
85struct connector {
86 drmModeConnector *connector;
87 drmModeObjectProperties *props;
88 drmModePropertyRes **props_info;
Thierry Redingf05a74f2015-01-23 17:08:21 +010089 char *name;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +010090};
91
92struct fb {
93 drmModeFB *fb;
94};
95
96struct plane {
97 drmModePlane *plane;
98 drmModeObjectProperties *props;
99 drmModePropertyRes **props_info;
100};
101
102struct resources {
103 drmModeRes *res;
104 drmModePlaneRes *plane_res;
105
106 struct crtc *crtcs;
107 struct encoder *encoders;
108 struct connector *connectors;
109 struct fb *fbs;
110 struct plane *planes;
111};
112
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100113struct device {
114 int fd;
115
116 struct resources *resources;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +0100117
118 struct {
119 unsigned int width;
120 unsigned int height;
121
122 unsigned int fb_id;
Laurent Pinchartd7c0a082014-12-09 22:00:58 +0200123 struct bo *bo;
Joonyoung Shim9915e682015-04-13 17:32:18 +0900124 struct bo *cursor_bo;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +0100125 } mode;
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100126};
Jesse Barnes731cd552008-12-17 10:09:49 -0800127
Rob Clarkfb417702013-10-12 12:16:44 -0400128static inline int64_t U642I64(uint64_t val)
129{
130 return (int64_t)*((int64_t *)&val);
131}
Jesse Barnes731cd552008-12-17 10:09:49 -0800132
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400133#define bit_name_fn(res) \
Laurent Pinchartca9c8f02013-02-11 21:36:30 +0100134const char * res##_str(int type) { \
135 unsigned int i; \
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400136 const char *sep = ""; \
137 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
138 if (type & (1 << i)) { \
139 printf("%s%s", sep, res##_names[i]); \
140 sep = ", "; \
141 } \
142 } \
Tobias Klausmann6fa2b292012-08-12 00:00:40 +0200143 return NULL; \
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400144}
145
146static const char *mode_type_names[] = {
147 "builtin",
148 "clock_c",
149 "crtc_c",
150 "preferred",
151 "default",
152 "userdef",
153 "driver",
154};
155
Laurent Pinchartca9c8f02013-02-11 21:36:30 +0100156static bit_name_fn(mode_type)
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400157
158static const char *mode_flag_names[] = {
159 "phsync",
160 "nhsync",
161 "pvsync",
162 "nvsync",
163 "interlace",
164 "dblscan",
165 "csync",
166 "pcsync",
167 "ncsync",
168 "hskew",
169 "bcast",
170 "pixmux",
171 "dblclk",
172 "clkdiv2"
173};
174
Laurent Pinchartca9c8f02013-02-11 21:36:30 +0100175static bit_name_fn(mode_flag)
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400176
Ilia Mirkin691a2152017-04-18 08:54:11 -0400177static void dump_fourcc(uint32_t fourcc)
178{
179 printf(" %c%c%c%c",
180 fourcc,
181 fourcc >> 8,
182 fourcc >> 16,
183 fourcc >> 24);
184}
185
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100186static void dump_encoders(struct device *dev)
Jesse Barnes731cd552008-12-17 10:09:49 -0800187{
188 drmModeEncoder *encoder;
189 int i;
190
191 printf("Encoders:\n");
192 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100193 for (i = 0; i < dev->resources->res->count_encoders; i++) {
194 encoder = dev->resources->encoders[i].encoder;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100195 if (!encoder)
Jesse Barnes731cd552008-12-17 10:09:49 -0800196 continue;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100197
Jesse Barnes731cd552008-12-17 10:09:49 -0800198 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
199 encoder->encoder_id,
200 encoder->crtc_id,
Thierry Reding4664d652015-12-09 18:37:40 +0100201 util_lookup_encoder_type_name(encoder->encoder_type),
Jesse Barnes731cd552008-12-17 10:09:49 -0800202 encoder->possible_crtcs,
203 encoder->possible_clones);
Jesse Barnes731cd552008-12-17 10:09:49 -0800204 }
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500205 printf("\n");
206}
207
Laurent Pinchartca9c8f02013-02-11 21:36:30 +0100208static void dump_mode(drmModeModeInfo *mode)
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500209{
Stéphane Marchesin72a04162016-08-31 19:45:45 -0700210 printf(" %s %d %d %d %d %d %d %d %d %d %d",
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500211 mode->name,
Marcin Kościelnicki694ef592010-02-27 15:04:42 +0000212 mode->vrefresh,
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500213 mode->hdisplay,
214 mode->hsync_start,
215 mode->hsync_end,
216 mode->htotal,
217 mode->vdisplay,
218 mode->vsync_start,
219 mode->vsync_end,
Stéphane Marchesin72a04162016-08-31 19:45:45 -0700220 mode->vtotal,
221 mode->clock);
Kristian Høgsbergc0ed9b22012-06-28 10:48:31 -0400222
223 printf(" flags: ");
224 mode_flag_str(mode->flags);
225 printf("; type: ");
226 mode_type_str(mode->type);
227 printf("\n");
Jesse Barnes731cd552008-12-17 10:09:49 -0800228}
229
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100230static void dump_blob(struct device *dev, uint32_t blob_id)
Kristian Høgsberg9fc85b42009-02-23 15:08:03 -0500231{
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300232 uint32_t i;
233 unsigned char *blob_data;
234 drmModePropertyBlobPtr blob;
Kristian Høgsberg9fc85b42009-02-23 15:08:03 -0500235
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100236 blob = drmModeGetPropertyBlob(dev->fd, blob_id);
Ville Syrjäläc2c03462012-06-08 13:28:16 +0300237 if (!blob) {
238 printf("\n");
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300239 return;
Ville Syrjäläc2c03462012-06-08 13:28:16 +0300240 }
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300241
242 blob_data = blob->data;
243
244 for (i = 0; i < blob->length; i++) {
245 if (i % 16 == 0)
246 printf("\n\t\t\t");
247 printf("%.2hhx", blob_data[i]);
Kristian Høgsberg9fc85b42009-02-23 15:08:03 -0500248 }
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300249 printf("\n");
250
251 drmModeFreePropertyBlob(blob);
252}
253
Kristian H. Kristensen511c71c2017-09-28 16:02:09 -0700254static const char *modifier_to_string(uint64_t modifier)
255{
256 switch (modifier) {
257 case DRM_FORMAT_MOD_INVALID:
258 return "INVALID";
259 case DRM_FORMAT_MOD_LINEAR:
260 return "LINEAR";
261 case I915_FORMAT_MOD_X_TILED:
262 return "X_TILED";
263 case I915_FORMAT_MOD_Y_TILED:
264 return "Y_TILED";
265 case I915_FORMAT_MOD_Yf_TILED:
266 return "Yf_TILED";
267 case I915_FORMAT_MOD_Y_TILED_CCS:
268 return "Y_TILED_CCS";
269 case I915_FORMAT_MOD_Yf_TILED_CCS:
270 return "Yf_TILED_CCS";
271 case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
272 return "SAMSUNG_64_32_TILE";
273 case DRM_FORMAT_MOD_VIVANTE_TILED:
274 return "VIVANTE_TILED";
275 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
276 return "VIVANTE_SUPER_TILED";
277 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
278 return "VIVANTE_SPLIT_TILED";
279 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
280 return "VIVANTE_SPLIT_SUPER_TILED";
281 case NV_FORMAT_MOD_TEGRA_TILED:
282 return "MOD_TEGRA_TILED";
283 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(0):
284 return "MOD_TEGRA_16BX2_BLOCK(0)";
285 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(1):
286 return "MOD_TEGRA_16BX2_BLOCK(1)";
287 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(2):
288 return "MOD_TEGRA_16BX2_BLOCK(2)";
289 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(3):
290 return "MOD_TEGRA_16BX2_BLOCK(3)";
291 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(4):
292 return "MOD_TEGRA_16BX2_BLOCK(4)";
293 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(5):
294 return "MOD_TEGRA_16BX2_BLOCK(5)";
295 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
296 return "MOD_BROADCOM_VC4_T_TILED";
297 default:
298 return "(UNKNOWN MODIFIER)";
299 }
300}
301
302static void dump_in_formats(struct device *dev, uint32_t blob_id)
303{
304 uint32_t i, j;
305 drmModePropertyBlobPtr blob;
306 struct drm_format_modifier_blob *header;
307 uint32_t *formats;
308 struct drm_format_modifier *modifiers;
309
310 printf("\t\tin_formats blob decoded:\n");
311 blob = drmModeGetPropertyBlob(dev->fd, blob_id);
312 if (!blob) {
313 printf("\n");
314 return;
315 }
316
317 header = blob->data;
318 formats = (uint32_t *) ((char *) header + header->formats_offset);
319 modifiers = (struct drm_format_modifier *)
320 ((char *) header + header->modifiers_offset);
321
322 for (i = 0; i < header->count_formats; i++) {
323 printf("\t\t\t");
324 dump_fourcc(formats[i]);
325 printf(": ");
326 for (j = 0; j < header->count_modifiers; j++) {
327 uint64_t mask = 1ULL << i;
328 if (modifiers[j].formats & mask)
329 printf(" %s", modifier_to_string(modifiers[j].modifier));
330 }
331 printf("\n");
332 }
333
334 drmModeFreePropertyBlob(blob);
335}
336
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100337static void dump_prop(struct device *dev, drmModePropertyPtr prop,
338 uint32_t prop_id, uint64_t value)
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300339{
340 int i;
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300341 printf("\t%d", prop_id);
342 if (!prop) {
343 printf("\n");
344 return;
345 }
346
347 printf(" %s:\n", prop->name);
348
349 printf("\t\tflags:");
350 if (prop->flags & DRM_MODE_PROP_PENDING)
351 printf(" pending");
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300352 if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
353 printf(" immutable");
Rob Clarkfb417702013-10-12 12:16:44 -0400354 if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
355 printf(" signed range");
356 if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE))
357 printf(" range");
358 if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM))
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300359 printf(" enum");
Rob Clarkfb417702013-10-12 12:16:44 -0400360 if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK))
Rob Clark6df9e6a2012-06-05 12:28:38 -0500361 printf(" bitmask");
Rob Clarkfb417702013-10-12 12:16:44 -0400362 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300363 printf(" blob");
Rob Clarkfb417702013-10-12 12:16:44 -0400364 if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT))
365 printf(" object");
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300366 printf("\n");
367
Rob Clarkfb417702013-10-12 12:16:44 -0400368 if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) {
369 printf("\t\tvalues:");
370 for (i = 0; i < prop->count_values; i++)
371 printf(" %"PRId64, U642I64(prop->values[i]));
372 printf("\n");
373 }
374
375 if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) {
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300376 printf("\t\tvalues:");
377 for (i = 0; i < prop->count_values; i++)
378 printf(" %"PRIu64, prop->values[i]);
379 printf("\n");
380 }
381
Rob Clarkfb417702013-10-12 12:16:44 -0400382 if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300383 printf("\t\tenums:");
384 for (i = 0; i < prop->count_enums; i++)
385 printf(" %s=%llu", prop->enums[i].name,
386 prop->enums[i].value);
387 printf("\n");
Rob Clarkfb417702013-10-12 12:16:44 -0400388 } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
Rob Clark6df9e6a2012-06-05 12:28:38 -0500389 printf("\t\tvalues:");
390 for (i = 0; i < prop->count_enums; i++)
391 printf(" %s=0x%llx", prop->enums[i].name,
392 (1LL << prop->enums[i].value));
393 printf("\n");
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300394 } else {
395 assert(prop->count_enums == 0);
396 }
397
Rob Clarkfb417702013-10-12 12:16:44 -0400398 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) {
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300399 printf("\t\tblobs:\n");
400 for (i = 0; i < prop->count_blobs; i++)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100401 dump_blob(dev, prop->blob_ids[i]);
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300402 printf("\n");
403 } else {
404 assert(prop->count_blobs == 0);
405 }
406
407 printf("\t\tvalue:");
Rob Clarkfb417702013-10-12 12:16:44 -0400408 if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100409 dump_blob(dev, value);
Gustavo Padovandfd8cd42016-03-22 18:42:52 -0300410 else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
411 printf(" %"PRId64"\n", value);
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300412 else
413 printf(" %"PRIu64"\n", value);
Kristian H. Kristensen511c71c2017-09-28 16:02:09 -0700414
415 if (strcmp(prop->name, "IN_FORMATS") == 0)
416 dump_in_formats(dev, value);
Kristian Høgsberg9fc85b42009-02-23 15:08:03 -0500417}
418
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100419static void dump_connectors(struct device *dev)
Jesse Barnes731cd552008-12-17 10:09:49 -0800420{
Jesse Barnes731cd552008-12-17 10:09:49 -0800421 int i, j;
422
423 printf("Connectors:\n");
Thierry Redingf05a74f2015-01-23 17:08:21 +0100424 printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100425 for (i = 0; i < dev->resources->res->count_connectors; i++) {
426 struct connector *_connector = &dev->resources->connectors[i];
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100427 drmModeConnector *connector = _connector->connector;
428 if (!connector)
Jesse Barnes731cd552008-12-17 10:09:49 -0800429 continue;
Jesse Barnes731cd552008-12-17 10:09:49 -0800430
Thierry Redingf05a74f2015-01-23 17:08:21 +0100431 printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t",
Jesse Barnes731cd552008-12-17 10:09:49 -0800432 connector->connector_id,
433 connector->encoder_id,
Thierry Reding4664d652015-12-09 18:37:40 +0100434 util_lookup_connector_status_name(connector->connection),
Thierry Redingf05a74f2015-01-23 17:08:21 +0100435 _connector->name,
Jesse Barnes731cd552008-12-17 10:09:49 -0800436 connector->mmWidth, connector->mmHeight,
437 connector->count_modes);
438
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -0500439 for (j = 0; j < connector->count_encoders; j++)
440 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
441 printf("\n");
442
Paulo Zanonia10bcaa2012-04-21 17:51:51 -0300443 if (connector->count_modes) {
444 printf(" modes:\n");
Paulo Zanonid72a44c2012-04-21 17:51:53 -0300445 printf("\tname refresh (Hz) hdisp hss hse htot vdisp "
Paulo Zanonia10bcaa2012-04-21 17:51:51 -0300446 "vss vse vtot)\n");
447 for (j = 0; j < connector->count_modes; j++)
448 dump_mode(&connector->modes[j]);
Paulo Zanonia10bcaa2012-04-21 17:51:51 -0300449 }
Marcin Kościelnicki9a374552010-02-27 15:04:40 +0000450
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100451 if (_connector->props) {
452 printf(" props:\n");
453 for (j = 0; j < (int)_connector->props->count_props; j++)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100454 dump_prop(dev, _connector->props_info[j],
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100455 _connector->props->props[j],
456 _connector->props->prop_values[j]);
457 }
Jesse Barnes731cd552008-12-17 10:09:49 -0800458 }
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500459 printf("\n");
Jesse Barnes731cd552008-12-17 10:09:49 -0800460}
461
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100462static void dump_crtcs(struct device *dev)
Jesse Barnes731cd552008-12-17 10:09:49 -0800463{
Jesse Barnes731cd552008-12-17 10:09:49 -0800464 int i;
Paulo Zanoni86dece42012-05-15 18:38:29 -0300465 uint32_t j;
Jesse Barnes731cd552008-12-17 10:09:49 -0800466
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500467 printf("CRTCs:\n");
468 printf("id\tfb\tpos\tsize\n");
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100469 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
470 struct crtc *_crtc = &dev->resources->crtcs[i];
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100471 drmModeCrtc *crtc = _crtc->crtc;
472 if (!crtc)
Jesse Barnes731cd552008-12-17 10:09:49 -0800473 continue;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100474
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500475 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
476 crtc->crtc_id,
477 crtc->buffer_id,
478 crtc->x, crtc->y,
479 crtc->width, crtc->height);
480 dump_mode(&crtc->mode);
481
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100482 if (_crtc->props) {
483 printf(" props:\n");
484 for (j = 0; j < _crtc->props->count_props; j++)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100485 dump_prop(dev, _crtc->props_info[j],
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100486 _crtc->props->props[j],
487 _crtc->props->prop_values[j]);
Paulo Zanoni86dece42012-05-15 18:38:29 -0300488 } else {
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100489 printf(" no properties found\n");
Paulo Zanoni86dece42012-05-15 18:38:29 -0300490 }
Jesse Barnes731cd552008-12-17 10:09:49 -0800491 }
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500492 printf("\n");
Jesse Barnes731cd552008-12-17 10:09:49 -0800493}
494
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100495static void dump_framebuffers(struct device *dev)
Jesse Barnes731cd552008-12-17 10:09:49 -0800496{
497 drmModeFB *fb;
498 int i;
499
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500500 printf("Frame buffers:\n");
501 printf("id\tsize\tpitch\n");
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100502 for (i = 0; i < dev->resources->res->count_fbs; i++) {
503 fb = dev->resources->fbs[i].fb;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100504 if (!fb)
Jesse Barnes731cd552008-12-17 10:09:49 -0800505 continue;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100506
Matthew W. S. Belle4a51962010-01-30 02:14:44 +0000507 printf("%u\t(%ux%u)\t%u\n",
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500508 fb->fb_id,
Matthew W. S. Belle4a51962010-01-30 02:14:44 +0000509 fb->width, fb->height,
510 fb->pitch);
Jesse Barnes731cd552008-12-17 10:09:49 -0800511 }
Kristian Høgsberg0243c9f2008-12-18 00:02:43 -0500512 printf("\n");
Jesse Barnes731cd552008-12-17 10:09:49 -0800513}
514
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100515static void dump_planes(struct device *dev)
Rob Clarkd55de742011-12-14 21:06:43 -0600516{
Paulo Zanoni9b44fbd2012-04-21 17:51:50 -0300517 unsigned int i, j;
Rob Clarkd55de742011-12-14 21:06:43 -0600518
Rob Clarkd55de742011-12-14 21:06:43 -0600519 printf("Planes:\n");
Ville Syrjälä8e565792013-04-17 19:18:04 +0000520 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100521
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100522 if (!dev->resources->plane_res)
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100523 return;
524
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100525 for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
526 struct plane *plane = &dev->resources->planes[i];
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100527 drmModePlane *ovr = plane->plane;
528 if (!ovr)
Rob Clarkd55de742011-12-14 21:06:43 -0600529 continue;
Rob Clarkd55de742011-12-14 21:06:43 -0600530
Ville Syrjälä8e565792013-04-17 19:18:04 +0000531 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
Rob Clarkd55de742011-12-14 21:06:43 -0600532 ovr->plane_id, ovr->crtc_id, ovr->fb_id,
533 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
Ville Syrjälä8e565792013-04-17 19:18:04 +0000534 ovr->gamma_size, ovr->possible_crtcs);
Rob Clarkd55de742011-12-14 21:06:43 -0600535
536 if (!ovr->count_formats)
537 continue;
538
539 printf(" formats:");
540 for (j = 0; j < ovr->count_formats; j++)
Ilia Mirkin691a2152017-04-18 08:54:11 -0400541 dump_fourcc(ovr->formats[j]);
Rob Clarkd55de742011-12-14 21:06:43 -0600542 printf("\n");
543
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100544 if (plane->props) {
545 printf(" props:\n");
546 for (j = 0; j < plane->props->count_props; j++)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100547 dump_prop(dev, plane->props_info[j],
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100548 plane->props->props[j],
549 plane->props->prop_values[j]);
Rob Clark25e4cb42012-06-05 12:28:47 -0500550 } else {
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100551 printf(" no properties found\n");
Rob Clark25e4cb42012-06-05 12:28:47 -0500552 }
Rob Clarkd55de742011-12-14 21:06:43 -0600553 }
554 printf("\n");
555
556 return;
557}
558
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100559static void free_resources(struct resources *res)
560{
Thierry Redingf05a74f2015-01-23 17:08:21 +0100561 int i;
562
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100563 if (!res)
564 return;
565
566#define free_resource(_res, __res, type, Type) \
567 do { \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100568 if (!(_res)->type##s) \
569 break; \
570 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
571 if (!(_res)->type##s[i].type) \
572 break; \
573 drmModeFree##Type((_res)->type##s[i].type); \
574 } \
575 free((_res)->type##s); \
576 } while (0)
577
578#define free_properties(_res, __res, type) \
579 do { \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100580 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
581 drmModeFreeObjectProperties(res->type##s[i].props); \
582 free(res->type##s[i].props_info); \
583 } \
584 } while (0)
585
586 if (res->res) {
587 free_properties(res, res, crtc);
588
589 free_resource(res, res, crtc, Crtc);
590 free_resource(res, res, encoder, Encoder);
Thierry Redingf05a74f2015-01-23 17:08:21 +0100591
592 for (i = 0; i < res->res->count_connectors; i++)
593 free(res->connectors[i].name);
594
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100595 free_resource(res, res, connector, Connector);
596 free_resource(res, res, fb, FB);
597
598 drmModeFreeResources(res->res);
599 }
600
601 if (res->plane_res) {
602 free_properties(res, plane_res, plane);
603
604 free_resource(res, plane_res, plane, Plane);
605
606 drmModeFreePlaneResources(res->plane_res);
607 }
608
609 free(res);
610}
611
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100612static struct resources *get_resources(struct device *dev)
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100613{
614 struct resources *res;
Laurent Pinchart56592682013-02-27 05:35:13 +0100615 int i;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100616
Emil Velikov128344c2015-04-28 13:25:24 +0100617 res = calloc(1, sizeof(*res));
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100618 if (res == 0)
619 return NULL;
620
Rob Clark1fec6232014-11-24 13:43:10 -0500621 drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
622
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100623 res->res = drmModeGetResources(dev->fd);
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100624 if (!res->res) {
625 fprintf(stderr, "drmModeGetResources failed: %s\n",
626 strerror(errno));
627 goto error;
628 }
629
Emil Velikov128344c2015-04-28 13:25:24 +0100630 res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs));
631 res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders));
632 res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors));
633 res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs));
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100634
635 if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
636 goto error;
637
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100638#define get_resource(_res, __res, type, Type) \
639 do { \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100640 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
641 (_res)->type##s[i].type = \
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100642 drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100643 if (!(_res)->type##s[i].type) \
644 fprintf(stderr, "could not get %s %i: %s\n", \
645 #type, (_res)->__res->type##s[i], \
646 strerror(errno)); \
647 } \
648 } while (0)
649
650 get_resource(res, res, crtc, Crtc);
651 get_resource(res, res, encoder, Encoder);
652 get_resource(res, res, connector, Connector);
653 get_resource(res, res, fb, FB);
654
Thierry Redingf05a74f2015-01-23 17:08:21 +0100655 /* Set the name of all connectors based on the type name and the per-type ID. */
656 for (i = 0; i < res->res->count_connectors; i++) {
657 struct connector *connector = &res->connectors[i];
Thierry Reding4664d652015-12-09 18:37:40 +0100658 drmModeConnector *conn = connector->connector;
Thierry Redingf05a74f2015-01-23 17:08:21 +0100659
660 asprintf(&connector->name, "%s-%u",
Thierry Reding4664d652015-12-09 18:37:40 +0100661 util_lookup_connector_type_name(conn->connector_type),
662 conn->connector_type_id);
Thierry Redingf05a74f2015-01-23 17:08:21 +0100663 }
664
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100665#define get_properties(_res, __res, type, Type) \
666 do { \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100667 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
668 struct type *obj = &res->type##s[i]; \
669 unsigned int j; \
670 obj->props = \
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100671 drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100672 DRM_MODE_OBJECT_##Type); \
673 if (!obj->props) { \
674 fprintf(stderr, \
675 "could not get %s %i properties: %s\n", \
676 #type, obj->type->type##_id, \
677 strerror(errno)); \
678 continue; \
679 } \
Emil Velikov128344c2015-04-28 13:25:24 +0100680 obj->props_info = calloc(obj->props->count_props, \
681 sizeof(*obj->props_info)); \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100682 if (!obj->props_info) \
683 continue; \
684 for (j = 0; j < obj->props->count_props; ++j) \
685 obj->props_info[j] = \
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100686 drmModeGetProperty(dev->fd, obj->props->props[j]); \
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100687 } \
688 } while (0)
689
690 get_properties(res, res, crtc, CRTC);
691 get_properties(res, res, connector, CONNECTOR);
692
Laurent Pinchart56592682013-02-27 05:35:13 +0100693 for (i = 0; i < res->res->count_crtcs; ++i)
694 res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
695
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100696 res->plane_res = drmModeGetPlaneResources(dev->fd);
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100697 if (!res->plane_res) {
698 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
699 strerror(errno));
700 return res;
701 }
702
Emil Velikov128344c2015-04-28 13:25:24 +0100703 res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes));
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100704 if (!res->planes)
705 goto error;
706
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100707 get_resource(res, plane_res, plane, Plane);
708 get_properties(res, plane_res, plane, PLANE);
709
710 return res;
711
712error:
713 free_resources(res);
714 return NULL;
715}
716
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100717static int get_crtc_index(struct device *dev, uint32_t id)
718{
719 int i;
720
721 for (i = 0; i < dev->resources->res->count_crtcs; ++i) {
722 drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
723 if (crtc && crtc->crtc_id == id)
724 return i;
725 }
726
727 return -1;
728}
729
Thierry Redingf05a74f2015-01-23 17:08:21 +0100730static drmModeConnector *get_connector_by_name(struct device *dev, const char *name)
731{
732 struct connector *connector;
733 int i;
734
735 for (i = 0; i < dev->resources->res->count_connectors; i++) {
736 connector = &dev->resources->connectors[i];
737
738 if (strcmp(connector->name, name) == 0)
739 return connector->connector;
740 }
741
742 return NULL;
743}
744
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100745static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
746{
747 drmModeConnector *connector;
748 int i;
749
750 for (i = 0; i < dev->resources->res->count_connectors; i++) {
751 connector = dev->resources->connectors[i].connector;
752 if (connector && connector->connector_id == id)
753 return connector;
754 }
755
756 return NULL;
757}
758
759static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
760{
761 drmModeEncoder *encoder;
762 int i;
763
764 for (i = 0; i < dev->resources->res->count_encoders; i++) {
765 encoder = dev->resources->encoders[i].encoder;
766 if (encoder && encoder->encoder_id == id)
767 return encoder;
768 }
769
770 return NULL;
771}
772
Laurent Pincharta94ee622012-07-20 14:50:42 +0200773/* -----------------------------------------------------------------------------
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +0100774 * Pipes and planes
Laurent Pincharta94ee622012-07-20 14:50:42 +0200775 */
776
Jesse Barnes731cd552008-12-17 10:09:49 -0800777/*
778 * Mode setting with the kernel interfaces is a bit of a chore.
779 * First you have to find the connector in question and make sure the
780 * requested mode is available.
781 * Then you need to find the encoder attached to that connector so you
782 * can bind it with a free crtc.
783 */
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +0100784struct pipe_arg {
Thierry Redingf05a74f2015-01-23 17:08:21 +0100785 const char **cons;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100786 uint32_t *con_ids;
787 unsigned int num_cons;
Laurent Pincharta6349d02013-02-27 05:35:13 +0100788 uint32_t crtc_id;
Kristian Høgsberg669fde32009-02-03 14:00:00 -0500789 char mode_str[64];
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +0200790 char format_str[5];
Vincent ABRIOUde097022014-01-10 11:02:33 +0100791 unsigned int vrefresh;
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +0200792 unsigned int fourcc;
Kristian Høgsberg9fc85b42009-02-23 15:08:03 -0500793 drmModeModeInfo *mode;
Laurent Pincharta6349d02013-02-27 05:35:13 +0100794 struct crtc *crtc;
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -0500795 unsigned int fb_id[2], current_fb_id;
796 struct timeval start;
797
798 int swap_count;
Rob Clarkd55de742011-12-14 21:06:43 -0600799};
800
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100801struct plane_arg {
Ville Syrjäläe3af5362016-07-19 19:47:13 +0300802 uint32_t plane_id; /* the id of plane to use */
Laurent Pincharteabf1992013-02-27 05:35:13 +0100803 uint32_t crtc_id; /* the id of CRTC to bind to */
Laurent Pinchart7badcca2013-02-27 05:35:13 +0100804 bool has_position;
805 int32_t x, y;
Rob Clarkd55de742011-12-14 21:06:43 -0600806 uint32_t w, h;
Ilia Mirkind8954152013-09-07 21:36:02 -0400807 double scale;
Rob Clarkd55de742011-12-14 21:06:43 -0600808 unsigned int fb_id;
Joonyoung Shim4d760d72015-04-28 11:41:39 +0100809 struct bo *bo;
Rob Clarkb83ad862011-12-14 22:24:14 -0600810 char format_str[5]; /* need to leave room for terminating \0 */
Laurent Pinchart03752222012-07-20 14:50:47 +0200811 unsigned int fourcc;
Rob Clarkd55de742011-12-14 21:06:43 -0600812};
Kristian Høgsberg669fde32009-02-03 14:00:00 -0500813
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100814static drmModeModeInfo *
Vincent ABRIOUde097022014-01-10 11:02:33 +0100815connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
816 const unsigned int vrefresh)
Jesse Barnes731cd552008-12-17 10:09:49 -0800817{
818 drmModeConnector *connector;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100819 drmModeModeInfo *mode;
820 int i;
Jesse Barnes731cd552008-12-17 10:09:49 -0800821
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100822 connector = get_connector_by_id(dev, con_id);
823 if (!connector || !connector->count_modes)
824 return NULL;
825
826 for (i = 0; i < connector->count_modes; i++) {
827 mode = &connector->modes[i];
Vincent ABRIOUde097022014-01-10 11:02:33 +0100828 if (!strcmp(mode->name, mode_str)) {
829 /* If the vertical refresh frequency is not specified then return the
830 * first mode that match with the name. Else, return the mode that match
831 * the name and the specified vertical refresh frequency.
832 */
833 if (vrefresh == 0)
834 return mode;
835 else if (mode->vrefresh == vrefresh)
836 return mode;
837 }
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100838 }
839
840 return NULL;
841}
842
843static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
844{
845 uint32_t possible_crtcs = ~0;
846 uint32_t active_crtcs = 0;
847 unsigned int crtc_idx;
848 unsigned int i;
849 int j;
850
851 for (i = 0; i < pipe->num_cons; ++i) {
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100852 uint32_t crtcs_for_connector = 0;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100853 drmModeConnector *connector;
854 drmModeEncoder *encoder;
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100855 int idx;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100856
857 connector = get_connector_by_id(dev, pipe->con_ids[i]);
Laurent Pinchart02fa8f72013-02-27 06:39:36 +0100858 if (!connector)
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100859 return NULL;
Jesse Barnes731cd552008-12-17 10:09:49 -0800860
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100861 for (j = 0; j < connector->count_encoders; ++j) {
862 encoder = get_encoder_by_id(dev, connector->encoders[j]);
863 if (!encoder)
864 continue;
Jesse Barnes731cd552008-12-17 10:09:49 -0800865
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100866 crtcs_for_connector |= encoder->possible_crtcs;
Jesse Barnes731cd552008-12-17 10:09:49 -0800867
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100868 idx = get_crtc_index(dev, encoder->crtc_id);
869 if (idx >= 0)
870 active_crtcs |= 1 << idx;
Laurent Pincharta6349d02013-02-27 05:35:13 +0100871 }
Laurent Pincharta4f2f1b2013-03-19 15:36:09 +0100872
873 possible_crtcs &= crtcs_for_connector;
Kristian Høgsberg669fde32009-02-03 14:00:00 -0500874 }
Kristian Høgsberg8b880362009-02-04 12:17:13 -0500875
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100876 if (!possible_crtcs)
877 return NULL;
Laurent Pincharta6349d02013-02-27 05:35:13 +0100878
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100879 /* Return the first possible and active CRTC if one exists, or the first
880 * possible CRTC otherwise.
881 */
882 if (possible_crtcs & active_crtcs)
883 crtc_idx = ffs(possible_crtcs & active_crtcs);
884 else
885 crtc_idx = ffs(possible_crtcs);
Laurent Pincharta6349d02013-02-27 05:35:13 +0100886
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100887 return &dev->resources->crtcs[crtc_idx - 1];
888}
889
890static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
891{
Emil Velikov4a8da022013-08-29 21:31:51 +0100892 drmModeModeInfo *mode = NULL;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100893 int i;
894
895 pipe->mode = NULL;
896
897 for (i = 0; i < (int)pipe->num_cons; i++) {
898 mode = connector_find_mode(dev, pipe->con_ids[i],
Vincent ABRIOUde097022014-01-10 11:02:33 +0100899 pipe->mode_str, pipe->vrefresh);
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100900 if (mode == NULL) {
901 fprintf(stderr,
Thierry Redingf05a74f2015-01-23 17:08:21 +0100902 "failed to find mode \"%s\" for connector %s\n",
903 pipe->mode_str, pipe->cons[i]);
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100904 return -EINVAL;
Laurent Pincharta6349d02013-02-27 05:35:13 +0100905 }
906 }
Laurent Pinchart2c5ee842013-03-19 13:48:36 +0100907
908 /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
909 * locate a CRTC that can be attached to all the connectors.
910 */
911 if (pipe->crtc_id != (uint32_t)-1) {
912 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
913 struct crtc *crtc = &dev->resources->crtcs[i];
914
915 if (pipe->crtc_id == crtc->crtc->crtc_id) {
916 pipe->crtc = crtc;
917 break;
918 }
919 }
920 } else {
921 pipe->crtc = pipe_find_crtc(dev, pipe);
922 }
923
924 if (!pipe->crtc) {
925 fprintf(stderr, "failed to find CRTC for pipe\n");
926 return -EINVAL;
927 }
928
929 pipe->mode = mode;
930 pipe->crtc->mode = mode;
931
932 return 0;
Kristian Høgsberg669fde32009-02-03 14:00:00 -0500933}
934
Laurent Pinchartd7252272013-02-27 05:35:13 +0100935/* -----------------------------------------------------------------------------
936 * Properties
937 */
938
939struct property_arg {
940 uint32_t obj_id;
941 uint32_t obj_type;
942 char name[DRM_PROP_NAME_LEN+1];
943 uint32_t prop_id;
944 uint64_t value;
945};
946
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100947static void set_property(struct device *dev, struct property_arg *p)
Laurent Pinchartd7252272013-02-27 05:35:13 +0100948{
Emil Velikov4a8da022013-08-29 21:31:51 +0100949 drmModeObjectProperties *props = NULL;
950 drmModePropertyRes **props_info = NULL;
Laurent Pinchartd7252272013-02-27 05:35:13 +0100951 const char *obj_type;
952 int ret;
953 int i;
954
955 p->obj_type = 0;
956 p->prop_id = 0;
957
958#define find_object(_res, __res, type, Type) \
959 do { \
960 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
961 struct type *obj = &(_res)->type##s[i]; \
962 if (obj->type->type##_id != p->obj_id) \
963 continue; \
964 p->obj_type = DRM_MODE_OBJECT_##Type; \
965 obj_type = #Type; \
966 props = obj->props; \
967 props_info = obj->props_info; \
968 } \
969 } while(0) \
970
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100971 find_object(dev->resources, res, crtc, CRTC);
Laurent Pinchartd7252272013-02-27 05:35:13 +0100972 if (p->obj_type == 0)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100973 find_object(dev->resources, res, connector, CONNECTOR);
Laurent Pinchartd7252272013-02-27 05:35:13 +0100974 if (p->obj_type == 0)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +0100975 find_object(dev->resources, plane_res, plane, PLANE);
Laurent Pinchartd7252272013-02-27 05:35:13 +0100976 if (p->obj_type == 0) {
977 fprintf(stderr, "Object %i not found, can't set property\n",
978 p->obj_id);
979 return;
980 }
981
982 if (!props) {
983 fprintf(stderr, "%s %i has no properties\n",
984 obj_type, p->obj_id);
985 return;
986 }
987
988 for (i = 0; i < (int)props->count_props; ++i) {
989 if (!props_info[i])
990 continue;
991 if (strcmp(props_info[i]->name, p->name) == 0)
992 break;
993 }
994
995 if (i == (int)props->count_props) {
996 fprintf(stderr, "%s %i has no %s property\n",
997 obj_type, p->obj_id, p->name);
998 return;
999 }
1000
1001 p->prop_id = props->props[i];
1002
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001003 ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
1004 p->prop_id, p->value);
Laurent Pinchartd7252272013-02-27 05:35:13 +01001005 if (ret < 0)
1006 fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
1007 obj_type, p->obj_id, p->name, p->value, strerror(errno));
1008}
1009
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001010/* -------------------------------------------------------------------------- */
1011
Laurent Pinchartca9c8f02013-02-11 21:36:30 +01001012static void
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001013page_flip_handler(int fd, unsigned int frame,
1014 unsigned int sec, unsigned int usec, void *data)
1015{
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001016 struct pipe_arg *pipe;
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001017 unsigned int new_fb_id;
1018 struct timeval end;
1019 double t;
1020
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001021 pipe = data;
1022 if (pipe->current_fb_id == pipe->fb_id[0])
1023 new_fb_id = pipe->fb_id[1];
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001024 else
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001025 new_fb_id = pipe->fb_id[0];
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001026
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001027 drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001028 DRM_MODE_PAGE_FLIP_EVENT, pipe);
1029 pipe->current_fb_id = new_fb_id;
1030 pipe->swap_count++;
1031 if (pipe->swap_count == 60) {
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001032 gettimeofday(&end, NULL);
1033 t = end.tv_sec + end.tv_usec * 1e-6 -
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001034 (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
1035 fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
1036 pipe->swap_count = 0;
1037 pipe->start = end;
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001038 }
1039}
1040
Tobias Jakobi360a7ea2015-05-06 14:29:33 +02001041static bool format_support(const drmModePlanePtr ovr, uint32_t fmt)
1042{
1043 unsigned int i;
1044
1045 for (i = 0; i < ovr->count_formats; ++i) {
1046 if (ovr->formats[i] == fmt)
1047 return true;
1048 }
1049
1050 return false;
1051}
1052
Laurent Pincharteabf1992013-02-27 05:35:13 +01001053static int set_plane(struct device *dev, struct plane_arg *p)
Rob Clarkd55de742011-12-14 21:06:43 -06001054{
Rob Clarkd55de742011-12-14 21:06:43 -06001055 drmModePlane *ovr;
Tobias Jakobib1d19de2015-04-20 21:50:45 +02001056 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001057 uint32_t plane_id;
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001058 struct bo *plane_bo;
Laurent Pinchart03752222012-07-20 14:50:47 +02001059 uint32_t plane_flags = 0;
Laurent Pinchartca9c8f02013-02-11 21:36:30 +01001060 int crtc_x, crtc_y, crtc_w, crtc_h;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001061 struct crtc *crtc = NULL;
Laurent Pinchart605efd72013-02-27 05:35:13 +01001062 unsigned int pipe;
Paulo Zanoni9b44fbd2012-04-21 17:51:50 -03001063 unsigned int i;
Rob Clarkd55de742011-12-14 21:06:43 -06001064
Laurent Pinchart605efd72013-02-27 05:35:13 +01001065 /* Find an unused plane which can be connected to our CRTC. Find the
1066 * CRTC index first, then iterate over available planes.
1067 */
1068 for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
Laurent Pincharteabf1992013-02-27 05:35:13 +01001069 if (p->crtc_id == dev->resources->res->crtcs[i]) {
1070 crtc = &dev->resources->crtcs[i];
Laurent Pinchart605efd72013-02-27 05:35:13 +01001071 pipe = i;
1072 break;
1073 }
1074 }
1075
Laurent Pincharteabf1992013-02-27 05:35:13 +01001076 if (!crtc) {
1077 fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
Laurent Pinchart605efd72013-02-27 05:35:13 +01001078 return -1;
1079 }
1080
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001081 plane_id = p->plane_id;
1082
1083 for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001084 ovr = dev->resources->planes[i].plane;
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001085 if (!ovr)
Laurent Pinchart02fa8f72013-02-27 06:39:36 +01001086 continue;
Rob Clarkd55de742011-12-14 21:06:43 -06001087
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001088 if (plane_id && plane_id != ovr->plane_id)
1089 continue;
1090
1091 if (!format_support(ovr, p->fourcc))
1092 continue;
1093
Ville Syrjäläba68d7b2017-10-11 17:58:11 +03001094 if ((ovr->possible_crtcs & (1 << pipe)) &&
1095 (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
Rob Clarkd55de742011-12-14 21:06:43 -06001096 plane_id = ovr->plane_id;
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001097 break;
1098 }
Rob Clarkd55de742011-12-14 21:06:43 -06001099 }
1100
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001101 if (i == dev->resources->plane_res->count_planes) {
Laurent Pincharteabf1992013-02-27 05:35:13 +01001102 fprintf(stderr, "no unused plane available for CRTC %u\n",
1103 crtc->crtc->crtc_id);
Rob Clarkd55de742011-12-14 21:06:43 -06001104 return -1;
1105 }
1106
Laurent Pinchart581c7cf2013-02-27 05:35:13 +01001107 fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
1108 p->w, p->h, p->format_str, plane_id);
1109
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001110 plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
Thierry Reding1ec3c442015-12-09 18:37:39 +01001111 pitches, offsets, UTIL_PATTERN_TILES);
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001112 if (plane_bo == NULL)
1113 return -1;
Rob Clarkd55de742011-12-14 21:06:43 -06001114
Joonyoung Shim4d760d72015-04-28 11:41:39 +01001115 p->bo = plane_bo;
1116
Rob Clarkd55de742011-12-14 21:06:43 -06001117 /* just use single plane format for now.. */
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001118 if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
Rob Clarkd55de742011-12-14 21:06:43 -06001119 handles, pitches, offsets, &p->fb_id, plane_flags)) {
1120 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
1121 return -1;
1122 }
1123
Ilia Mirkind8954152013-09-07 21:36:02 -04001124 crtc_w = p->w * p->scale;
1125 crtc_h = p->h * p->scale;
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001126 if (!p->has_position) {
1127 /* Default to the middle of the screen */
Ilia Mirkind8954152013-09-07 21:36:02 -04001128 crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
1129 crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001130 } else {
1131 crtc_x = p->x;
1132 crtc_y = p->y;
1133 }
Rob Clarkd55de742011-12-14 21:06:43 -06001134
1135 /* note src coords (last 4 args) are in Q16 format */
Laurent Pincharteabf1992013-02-27 05:35:13 +01001136 if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id,
Rob Clarkd55de742011-12-14 21:06:43 -06001137 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
1138 0, 0, p->w << 16, p->h << 16)) {
1139 fprintf(stderr, "failed to enable plane: %s\n",
1140 strerror(errno));
1141 return -1;
1142 }
1143
Laurent Pincharteabf1992013-02-27 05:35:13 +01001144 ovr->crtc_id = crtc->crtc->crtc_id;
Laurent Pinchart02fa8f72013-02-27 06:39:36 +01001145
Rob Clarkd55de742011-12-14 21:06:43 -06001146 return 0;
1147}
1148
Joonyoung Shim4d760d72015-04-28 11:41:39 +01001149static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
1150{
1151 unsigned int i;
1152
1153 for (i = 0; i < count; i++) {
1154 if (p[i].fb_id)
1155 drmModeRmFB(dev->fd, p[i].fb_id);
1156 if (p[i].bo)
1157 bo_destroy(p[i].bo);
1158 }
1159}
1160
1161
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001162static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001163{
Tobias Jakobib1d19de2015-04-20 21:50:45 +02001164 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001165 unsigned int fb_id;
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001166 struct bo *bo;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001167 unsigned int i;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001168 unsigned int j;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001169 int ret, x;
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001170
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001171 dev->mode.width = 0;
1172 dev->mode.height = 0;
Joonyoung Shimbcaaa752015-04-13 17:32:15 +09001173 dev->mode.fb_id = 0;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001174
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001175 for (i = 0; i < count; i++) {
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001176 struct pipe_arg *pipe = &pipes[i];
1177
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001178 ret = pipe_find_crtc_and_mode(dev, pipe);
1179 if (ret < 0)
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001180 continue;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001181
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001182 dev->mode.width += pipe->mode->hdisplay;
1183 if (dev->mode.height < pipe->mode->vdisplay)
1184 dev->mode.height = pipe->mode->vdisplay;
Jesse Barnes731cd552008-12-17 10:09:49 -08001185 }
1186
Thierry Reding1ec3c442015-12-09 18:37:39 +01001187 bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
1188 dev->mode.height, handles, pitches, offsets,
1189 UTIL_PATTERN_SMPTE);
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001190 if (bo == NULL)
Jesse Barnes731cd552008-12-17 10:09:49 -08001191 return;
Jesse Barnes731cd552008-12-17 10:09:49 -08001192
Joonyoung Shim21170a82015-04-13 17:32:16 +09001193 dev->mode.bo = bo;
1194
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001195 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
1196 pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
Jesse Barnes731cd552008-12-17 10:09:49 -08001197 if (ret) {
Jakob Bornecrantz680b9c42011-10-19 13:32:26 +02001198 fprintf(stderr, "failed to add fb (%ux%u): %s\n",
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001199 dev->mode.width, dev->mode.height, strerror(errno));
Jesse Barnes731cd552008-12-17 10:09:49 -08001200 return;
1201 }
1202
Joonyoung Shim21170a82015-04-13 17:32:16 +09001203 dev->mode.fb_id = fb_id;
1204
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001205 x = 0;
1206 for (i = 0; i < count; i++) {
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001207 struct pipe_arg *pipe = &pipes[i];
1208
1209 if (pipe->mode == NULL)
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001210 continue;
Kristian Høgsberg8b880362009-02-04 12:17:13 -05001211
Vincent ABRIOUde097022014-01-10 11:02:33 +01001212 printf("setting mode %s-%dHz@%s on connectors ",
1213 pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001214 for (j = 0; j < pipe->num_cons; ++j)
Thierry Redingf05a74f2015-01-23 17:08:21 +01001215 printf("%s, ", pipe->cons[j]);
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001216 printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
Kristian Høgsberg8b880362009-02-04 12:17:13 -05001217
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001218 ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
1219 x, 0, pipe->con_ids, pipe->num_cons,
1220 pipe->mode);
Jakob Bornecrantzd23146f2011-10-19 13:32:43 +02001221
1222 /* XXX: Actually check if this is needed */
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001223 drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
Jakob Bornecrantzd23146f2011-10-19 13:32:43 +02001224
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001225 x += pipe->mode->hdisplay;
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001226
1227 if (ret) {
1228 fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
1229 return;
1230 }
Jesse Barnes731cd552008-12-17 10:09:49 -08001231 }
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001232}
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001233
Joonyoung Shim4e4d79d2015-04-13 17:32:14 +09001234static void clear_mode(struct device *dev)
1235{
Joonyoung Shimbcaaa752015-04-13 17:32:15 +09001236 if (dev->mode.fb_id)
1237 drmModeRmFB(dev->fd, dev->mode.fb_id);
Joonyoung Shim4e4d79d2015-04-13 17:32:14 +09001238 if (dev->mode.bo)
1239 bo_destroy(dev->mode.bo);
1240}
1241
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001242static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count)
1243{
1244 unsigned int i;
1245
1246 /* set up planes/overlays */
1247 for (i = 0; i < count; i++)
1248 if (set_plane(dev, &p[i]))
1249 return;
1250}
1251
Rob Clark0e512792014-04-22 10:33:12 -04001252static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
1253{
Tobias Jakobib1d19de2015-04-20 21:50:45 +02001254 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001255 struct bo *bo;
Rob Clark0e512792014-04-22 10:33:12 -04001256 unsigned int i;
1257 int ret;
1258
1259 /* maybe make cursor width/height configurable some day */
1260 uint32_t cw = 64;
1261 uint32_t ch = 64;
1262
1263 /* create cursor bo.. just using PATTERN_PLAIN as it has
1264 * translucent alpha
1265 */
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001266 bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches,
Thierry Reding1ec3c442015-12-09 18:37:39 +01001267 offsets, UTIL_PATTERN_PLAIN);
Rob Clark0e512792014-04-22 10:33:12 -04001268 if (bo == NULL)
1269 return;
1270
Joonyoung Shim9915e682015-04-13 17:32:18 +09001271 dev->mode.cursor_bo = bo;
1272
Rob Clark0e512792014-04-22 10:33:12 -04001273 for (i = 0; i < count; i++) {
1274 struct pipe_arg *pipe = &pipes[i];
1275 ret = cursor_init(dev->fd, handles[0],
1276 pipe->crtc->crtc->crtc_id,
1277 pipe->mode->hdisplay, pipe->mode->vdisplay,
1278 cw, ch);
1279 if (ret) {
1280 fprintf(stderr, "failed to init cursor for CRTC[%u]\n",
1281 pipe->crtc_id);
1282 return;
1283 }
1284 }
1285
1286 cursor_start();
1287}
1288
1289static void clear_cursors(struct device *dev)
1290{
1291 cursor_stop();
Joonyoung Shim9915e682015-04-13 17:32:18 +09001292
1293 if (dev->mode.cursor_bo)
1294 bo_destroy(dev->mode.cursor_bo);
Rob Clark0e512792014-04-22 10:33:12 -04001295}
1296
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001297static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001298{
Tobias Jakobib1d19de2015-04-20 21:50:45 +02001299 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001300 unsigned int other_fb_id;
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001301 struct bo *other_bo;
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001302 drmEventContext evctx;
1303 unsigned int i;
1304 int ret;
1305
Thierry Reding1ec3c442015-12-09 18:37:39 +01001306 other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
1307 dev->mode.height, handles, pitches, offsets,
1308 UTIL_PATTERN_PLAIN);
Laurent Pinchart3fdc1772012-07-20 14:50:41 +02001309 if (other_bo == NULL)
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001310 return;
1311
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001312 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
1313 pipes[0].fourcc, handles, pitches, offsets,
1314 &other_fb_id, 0);
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001315 if (ret) {
1316 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
Joonyoung Shim21170a82015-04-13 17:32:16 +09001317 goto err;
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001318 }
1319
1320 for (i = 0; i < count; i++) {
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001321 struct pipe_arg *pipe = &pipes[i];
1322
1323 if (pipe->mode == NULL)
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001324 continue;
1325
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001326 ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
1327 other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1328 pipe);
Jakob Bornecrantz3c8adda2011-09-28 23:34:09 +02001329 if (ret) {
1330 fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
Joonyoung Shim21170a82015-04-13 17:32:16 +09001331 goto err_rmfb;
Jakob Bornecrantz3c8adda2011-09-28 23:34:09 +02001332 }
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001333 gettimeofday(&pipe->start, NULL);
1334 pipe->swap_count = 0;
1335 pipe->fb_id[0] = dev->mode.fb_id;
1336 pipe->fb_id[1] = other_fb_id;
1337 pipe->current_fb_id = other_fb_id;
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001338 }
1339
1340 memset(&evctx, 0, sizeof evctx);
1341 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1342 evctx.vblank_handler = NULL;
Jesse Barnes6f1eba02009-12-04 09:09:19 -08001343 evctx.page_flip_handler = page_flip_handler;
Hyungwon Hwang6e84ada2015-08-19 09:58:42 +09001344
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001345 while (1) {
Jesse Barnese6b3f902010-03-26 13:13:57 -07001346#if 0
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001347 struct pollfd pfd[2];
1348
1349 pfd[0].fd = 0;
1350 pfd[0].events = POLLIN;
1351 pfd[1].fd = fd;
1352 pfd[1].events = POLLIN;
1353
1354 if (poll(pfd, 2, -1) < 0) {
1355 fprintf(stderr, "poll error\n");
1356 break;
1357 }
1358
1359 if (pfd[0].revents)
1360 break;
Jesse Barnese6b3f902010-03-26 13:13:57 -07001361#else
1362 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
1363 fd_set fds;
Jesse Barnese6b3f902010-03-26 13:13:57 -07001364
1365 FD_ZERO(&fds);
1366 FD_SET(0, &fds);
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001367 FD_SET(dev->fd, &fds);
1368 ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
Jesse Barnese6b3f902010-03-26 13:13:57 -07001369
1370 if (ret <= 0) {
1371 fprintf(stderr, "select timed out or error (ret %d)\n",
1372 ret);
1373 continue;
1374 } else if (FD_ISSET(0, &fds)) {
1375 break;
1376 }
1377#endif
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001378
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001379 drmHandleEvent(dev->fd, &evctx);
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001380 }
Benjamin Franzke8fef2902011-02-17 10:47:47 +01001381
Joonyoung Shim21170a82015-04-13 17:32:16 +09001382err_rmfb:
Joonyoung Shimbcaaa752015-04-13 17:32:15 +09001383 drmModeRmFB(dev->fd, other_fb_id);
Joonyoung Shim21170a82015-04-13 17:32:16 +09001384err:
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001385 bo_destroy(other_bo);
Jesse Barnes731cd552008-12-17 10:09:49 -08001386}
1387
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001388#define min(a, b) ((a) < (b) ? (a) : (b))
1389
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001390static int parse_connector(struct pipe_arg *pipe, const char *arg)
Laurent Pinchart03752222012-07-20 14:50:47 +02001391{
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001392 unsigned int len;
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001393 unsigned int i;
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001394 const char *p;
1395 char *endp;
1396
Vincent ABRIOUde097022014-01-10 11:02:33 +01001397 pipe->vrefresh = 0;
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001398 pipe->crtc_id = (uint32_t)-1;
1399 strcpy(pipe->format_str, "XR24");
Laurent Pinchart03752222012-07-20 14:50:47 +02001400
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001401 /* Count the number of connectors and allocate them. */
1402 pipe->num_cons = 1;
Thierry Redingf05a74f2015-01-23 17:08:21 +01001403 for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001404 if (*p == ',')
1405 pipe->num_cons++;
1406 }
1407
Emil Velikov128344c2015-04-28 13:25:24 +01001408 pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
Thierry Redingf05a74f2015-01-23 17:08:21 +01001409 pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
1410 if (pipe->con_ids == NULL || pipe->cons == NULL)
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001411 return -1;
1412
1413 /* Parse the connectors. */
1414 for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
Thierry Redingf05a74f2015-01-23 17:08:21 +01001415 endp = strpbrk(p, ",@:");
1416 if (!endp)
1417 break;
1418
1419 pipe->cons[i] = strndup(p, endp - p);
1420
Laurent Pinchart2c5ee842013-03-19 13:48:36 +01001421 if (*endp != ',')
1422 break;
1423 }
1424
1425 if (i != pipe->num_cons - 1)
1426 return -1;
1427
1428 /* Parse the remaining parameters. */
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001429 if (*endp == '@') {
1430 arg = endp + 1;
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001431 pipe->crtc_id = strtoul(arg, &endp, 10);
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001432 }
1433 if (*endp != ':')
1434 return -1;
Laurent Pinchart03752222012-07-20 14:50:47 +02001435
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001436 arg = endp + 1;
Laurent Pinchart03752222012-07-20 14:50:47 +02001437
Vincent ABRIOUde097022014-01-10 11:02:33 +01001438 /* Search for the vertical refresh or the format. */
1439 p = strpbrk(arg, "-@");
1440 if (p == NULL)
1441 p = arg + strlen(arg);
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001442 len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg));
1443 strncpy(pipe->mode_str, arg, len);
1444 pipe->mode_str[len] = '\0';
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001445
Vincent ABRIOUde097022014-01-10 11:02:33 +01001446 if (*p == '-') {
1447 pipe->vrefresh = strtoul(p + 1, &endp, 10);
1448 p = endp;
1449 }
1450
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001451 if (*p == '@') {
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001452 strncpy(pipe->format_str, p + 1, 4);
1453 pipe->format_str[4] = '\0';
Rob Clarkebd79042012-07-23 11:35:06 -05001454 }
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001455
Thierry Reding1ec3c442015-12-09 18:37:39 +01001456 pipe->fourcc = util_format_fourcc(pipe->format_str);
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001457 if (pipe->fourcc == 0) {
1458 fprintf(stderr, "unknown format %s\n", pipe->format_str);
Rob Clarkebd79042012-07-23 11:35:06 -05001459 return -1;
Laurent Pinchartcc90ffa2012-07-20 14:50:48 +02001460 }
1461
1462 return 0;
Laurent Pinchart03752222012-07-20 14:50:47 +02001463}
1464
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001465static int parse_plane(struct plane_arg *plane, const char *p)
Laurent Pinchart03752222012-07-20 14:50:47 +02001466{
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001467 char *end;
Laurent Pinchart03752222012-07-20 14:50:47 +02001468
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001469 plane->plane_id = strtoul(p, &end, 10);
1470 if (*end != '@')
1471 return -EINVAL;
1472
1473 p = end + 1;
Laurent Pincharteabf1992013-02-27 05:35:13 +01001474 plane->crtc_id = strtoul(p, &end, 10);
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001475 if (*end != ':')
1476 return -EINVAL;
1477
1478 p = end + 1;
1479 plane->w = strtoul(p, &end, 10);
1480 if (*end != 'x')
1481 return -EINVAL;
1482
1483 p = end + 1;
1484 plane->h = strtoul(p, &end, 10);
1485
1486 if (*end == '+' || *end == '-') {
1487 plane->x = strtol(end, &end, 10);
1488 if (*end != '+' && *end != '-')
1489 return -EINVAL;
1490 plane->y = strtol(end, &end, 10);
1491
1492 plane->has_position = true;
1493 }
1494
Ilia Mirkind8954152013-09-07 21:36:02 -04001495 if (*end == '*') {
1496 p = end + 1;
1497 plane->scale = strtod(p, &end);
1498 if (plane->scale <= 0.0)
1499 return -EINVAL;
1500 } else {
1501 plane->scale = 1.0;
1502 }
1503
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001504 if (*end == '@') {
1505 p = end + 1;
1506 if (strlen(p) != 4)
1507 return -EINVAL;
1508
1509 strcpy(plane->format_str, p);
1510 } else {
1511 strcpy(plane->format_str, "XR24");
1512 }
1513
Thierry Reding1ec3c442015-12-09 18:37:39 +01001514 plane->fourcc = util_format_fourcc(plane->format_str);
Laurent Pinchart7badcca2013-02-27 05:35:13 +01001515 if (plane->fourcc == 0) {
1516 fprintf(stderr, "unknown format %s\n", plane->format_str);
1517 return -EINVAL;
Laurent Pinchart03752222012-07-20 14:50:47 +02001518 }
1519
1520 return 0;
1521}
1522
Laurent Pinchartd7252272013-02-27 05:35:13 +01001523static int parse_property(struct property_arg *p, const char *arg)
1524{
1525 if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
1526 return -1;
1527
1528 p->obj_type = 0;
1529 p->name[DRM_PROP_NAME_LEN] = '\0';
1530
1531 return 0;
1532}
1533
Laurent Pinchartca9c8f02013-02-11 21:36:30 +01001534static void usage(char *name)
Jesse Barnes731cd552008-12-17 10:09:49 -08001535{
Rob Clark0e512792014-04-22 10:33:12 -04001536 fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name);
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001537
1538 fprintf(stderr, "\n Query options:\n\n");
Jesse Barnes731cd552008-12-17 10:09:49 -08001539 fprintf(stderr, "\t-c\tlist connectors\n");
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001540 fprintf(stderr, "\t-e\tlist encoders\n");
Jesse Barnes731cd552008-12-17 10:09:49 -08001541 fprintf(stderr, "\t-f\tlist framebuffers\n");
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001542 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
1543
1544 fprintf(stderr, "\n Test options:\n\n");
Ville Syrjäläe3af5362016-07-19 19:47:13 +03001545 fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
Vincent ABRIOUde097022014-01-10 11:02:33 +01001546 fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
Rob Clark0e512792014-04-22 10:33:12 -04001547 fprintf(stderr, "\t-C\ttest hw cursor\n");
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001548 fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
Laurent Pinchartd7252272013-02-27 05:35:13 +01001549 fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001550
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001551 fprintf(stderr, "\n Generic options:\n\n");
Laurent Pinchartab527562013-02-27 05:19:44 +01001552 fprintf(stderr, "\t-d\tdrop master after mode set\n");
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001553 fprintf(stderr, "\t-M module\tuse the given driver\n");
Ilia Mirkinb50826d2013-09-07 21:36:01 -04001554 fprintf(stderr, "\t-D device\tuse the given device\n");
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001555
Jesse Barnes731cd552008-12-17 10:09:49 -08001556 fprintf(stderr, "\n\tDefault is to dump all info.\n");
1557 exit(0);
1558}
1559
Paulo Zanoni9b44fbd2012-04-21 17:51:50 -03001560static int page_flipping_supported(void)
Kristian Høgsberg59d97e72009-12-09 10:36:53 -05001561{
Benjamin Franzke8fef2902011-02-17 10:47:47 +01001562 /*FIXME: generic ioctl needed? */
1563 return 1;
1564#if 0
Kristian Høgsberg59d97e72009-12-09 10:36:53 -05001565 int ret, value;
1566 struct drm_i915_getparam gp;
1567
1568 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
1569 gp.value = &value;
1570
1571 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
1572 if (ret) {
1573 fprintf(stderr, "drm_i915_getparam: %m\n");
1574 return 0;
1575 }
1576
Matthew W. S. Belle4a51962010-01-30 02:14:44 +00001577 return *gp.value;
Benjamin Franzke8fef2902011-02-17 10:47:47 +01001578#endif
Kristian Høgsberg59d97e72009-12-09 10:36:53 -05001579}
1580
Rob Clark0e512792014-04-22 10:33:12 -04001581static int cursor_supported(void)
1582{
1583 /*FIXME: generic ioctl needed? */
1584 return 1;
1585}
1586
Thierry Redingf05a74f2015-01-23 17:08:21 +01001587static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
1588{
1589 drmModeConnector *connector;
1590 unsigned int i;
1591 uint32_t id;
1592 char *endp;
1593
1594 for (i = 0; i < pipe->num_cons; i++) {
1595 id = strtoul(pipe->cons[i], &endp, 10);
1596 if (endp == pipe->cons[i]) {
1597 connector = get_connector_by_name(dev, pipe->cons[i]);
1598 if (!connector) {
1599 fprintf(stderr, "no connector named '%s'\n",
1600 pipe->cons[i]);
1601 return -ENODEV;
1602 }
1603
1604 id = connector->connector_id;
1605 }
1606
1607 pipe->con_ids[i] = id;
1608 }
1609
1610 return 0;
1611}
1612
Rob Clark0e512792014-04-22 10:33:12 -04001613static char optstr[] = "cdD:efM:P:ps:Cvw:";
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001614
Jesse Barnes731cd552008-12-17 10:09:49 -08001615int main(int argc, char **argv)
1616{
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001617 struct device dev;
1618
Jesse Barnes731cd552008-12-17 10:09:49 -08001619 int c;
Rob Clarkd55de742011-12-14 21:06:43 -06001620 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
Laurent Pinchartab527562013-02-27 05:19:44 +01001621 int drop_master = 0;
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001622 int test_vsync = 0;
Rob Clark0e512792014-04-22 10:33:12 -04001623 int test_cursor = 0;
Ilia Mirkinb50826d2013-09-07 21:36:01 -04001624 char *device = NULL;
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001625 char *module = NULL;
Paulo Zanoni9b44fbd2012-04-21 17:51:50 -03001626 unsigned int i;
Thierry Redingf05a74f2015-01-23 17:08:21 +01001627 unsigned int count = 0, plane_count = 0;
Laurent Pinchartd7252272013-02-27 05:35:13 +01001628 unsigned int prop_count = 0;
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001629 struct pipe_arg *pipe_args = NULL;
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001630 struct plane_arg *plane_args = NULL;
Laurent Pinchartd7252272013-02-27 05:35:13 +01001631 struct property_arg *prop_args = NULL;
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001632 unsigned int args = 0;
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001633 int ret;
1634
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001635 memset(&dev, 0, sizeof dev);
1636
Jesse Barnes731cd552008-12-17 10:09:49 -08001637 opterr = 0;
1638 while ((c = getopt(argc, argv, optstr)) != -1) {
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001639 args++;
1640
Jesse Barnes731cd552008-12-17 10:09:49 -08001641 switch (c) {
Jesse Barnes731cd552008-12-17 10:09:49 -08001642 case 'c':
1643 connectors = 1;
1644 break;
Ilia Mirkinb50826d2013-09-07 21:36:01 -04001645 case 'D':
1646 device = optarg;
1647 args--;
1648 break;
Laurent Pinchartab527562013-02-27 05:19:44 +01001649 case 'd':
1650 drop_master = 1;
1651 break;
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001652 case 'e':
1653 encoders = 1;
Jesse Barnes731cd552008-12-17 10:09:49 -08001654 break;
1655 case 'f':
1656 framebuffers = 1;
1657 break;
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001658 case 'M':
1659 module = optarg;
1660 /* Preserve the default behaviour of dumping all information. */
1661 args--;
1662 break;
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001663 case 'P':
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001664 plane_args = realloc(plane_args,
1665 (plane_count + 1) * sizeof *plane_args);
1666 if (plane_args == NULL) {
1667 fprintf(stderr, "memory allocation failed\n");
1668 return 1;
1669 }
Emil Velikovc78917e2015-04-28 14:20:30 +01001670 memset(&plane_args[plane_count], 0, sizeof(*plane_args));
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001671
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001672 if (parse_plane(&plane_args[plane_count], optarg) < 0)
1673 usage(argv[0]);
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001674
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001675 plane_count++;
1676 break;
1677 case 'p':
1678 crtcs = 1;
1679 planes = 1;
Kristian Høgsberg1e1b3c02009-11-17 15:32:23 -05001680 break;
Jesse Barnes731cd552008-12-17 10:09:49 -08001681 case 's':
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001682 pipe_args = realloc(pipe_args,
1683 (count + 1) * sizeof *pipe_args);
1684 if (pipe_args == NULL) {
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001685 fprintf(stderr, "memory allocation failed\n");
1686 return 1;
1687 }
Emil Velikovc78917e2015-04-28 14:20:30 +01001688 memset(&pipe_args[count], 0, sizeof(*pipe_args));
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001689
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001690 if (parse_connector(&pipe_args[count], optarg) < 0)
Kristian Høgsberg669fde32009-02-03 14:00:00 -05001691 usage(argv[0]);
Laurent Pinchart6e0c74c2013-03-01 02:28:42 +01001692
Hyungwon Hwang6e84ada2015-08-19 09:58:42 +09001693 count++;
Jesse Barnes731cd552008-12-17 10:09:49 -08001694 break;
Rob Clark0e512792014-04-22 10:33:12 -04001695 case 'C':
1696 test_cursor = 1;
1697 break;
Laurent Pinchartef07acf2013-02-08 11:12:03 +01001698 case 'v':
1699 test_vsync = 1;
Rob Clarkd55de742011-12-14 21:06:43 -06001700 break;
Laurent Pinchartd7252272013-02-27 05:35:13 +01001701 case 'w':
1702 prop_args = realloc(prop_args,
1703 (prop_count + 1) * sizeof *prop_args);
1704 if (prop_args == NULL) {
1705 fprintf(stderr, "memory allocation failed\n");
1706 return 1;
1707 }
Emil Velikovc78917e2015-04-28 14:20:30 +01001708 memset(&prop_args[prop_count], 0, sizeof(*prop_args));
Laurent Pinchartd7252272013-02-27 05:35:13 +01001709
1710 if (parse_property(&prop_args[prop_count], optarg) < 0)
1711 usage(argv[0]);
1712
1713 prop_count++;
1714 break;
Jesse Barnes731cd552008-12-17 10:09:49 -08001715 default:
1716 usage(argv[0]);
1717 break;
1718 }
1719 }
1720
Laurent Pinchart45901fd2013-02-08 13:42:45 +01001721 if (!args)
Laurent Pinchartdab3c802013-02-27 05:35:13 +01001722 encoders = connectors = crtcs = planes = framebuffers = 1;
Jesse Barnes731cd552008-12-17 10:09:49 -08001723
Thierry Reding16741472016-01-05 15:21:23 +01001724 dev.fd = util_open(device, module);
Thierry Redingc26266f2015-12-09 18:37:46 +01001725 if (dev.fd < 0)
1726 return -1;
Jesse Barnes731cd552008-12-17 10:09:49 -08001727
Paulo Zanoni9b44fbd2012-04-21 17:51:50 -03001728 if (test_vsync && !page_flipping_supported()) {
Kristian Høgsberg59d97e72009-12-09 10:36:53 -05001729 fprintf(stderr, "page flipping not supported by drm.\n");
1730 return -1;
1731 }
1732
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001733 if (test_vsync && !count) {
1734 fprintf(stderr, "page flipping requires at least one -s option.\n");
1735 return -1;
1736 }
1737
Rob Clark0e512792014-04-22 10:33:12 -04001738 if (test_cursor && !cursor_supported()) {
1739 fprintf(stderr, "hw cursor not supported by drm.\n");
1740 return -1;
1741 }
1742
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001743 dev.resources = get_resources(&dev);
1744 if (!dev.resources) {
1745 drmClose(dev.fd);
Jesse Barnes731cd552008-12-17 10:09:49 -08001746 return 1;
1747 }
1748
Thierry Redingf05a74f2015-01-23 17:08:21 +01001749 for (i = 0; i < count; i++) {
1750 if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) {
1751 free_resources(dev.resources);
1752 drmClose(dev.fd);
1753 return 1;
1754 }
1755 }
1756
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001757#define dump_resource(dev, res) if (res) dump_##res(dev)
1758
1759 dump_resource(&dev, encoders);
1760 dump_resource(&dev, connectors);
1761 dump_resource(&dev, crtcs);
1762 dump_resource(&dev, planes);
1763 dump_resource(&dev, framebuffers);
Jesse Barnes731cd552008-12-17 10:09:49 -08001764
Laurent Pinchartd7252272013-02-27 05:35:13 +01001765 for (i = 0; i < prop_count; ++i)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001766 set_property(&dev, &prop_args[i]);
Laurent Pinchartd7252272013-02-27 05:35:13 +01001767
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001768 if (count || plane_count) {
Laurent Pinchartd7c0a082014-12-09 22:00:58 +02001769 uint64_t cap = 0;
1770
1771 ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
1772 if (ret || cap == 0) {
1773 fprintf(stderr, "driver doesn't support the dumb buffer API\n");
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001774 return 1;
1775 }
1776
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001777 if (count)
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001778 set_mode(&dev, pipe_args, count);
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001779
1780 if (plane_count)
1781 set_planes(&dev, plane_args, plane_count);
1782
Rob Clark0e512792014-04-22 10:33:12 -04001783 if (test_cursor)
1784 set_cursors(&dev, pipe_args, count);
1785
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001786 if (test_vsync)
Laurent Pinchartb1e0bde2013-03-19 13:47:39 +01001787 test_page_flip(&dev, pipe_args, count);
Laurent Pinchart3813e0f2013-02-27 05:35:13 +01001788
Laurent Pinchartab527562013-02-27 05:19:44 +01001789 if (drop_master)
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001790 drmDropMaster(dev.fd);
1791
Rob Clark0e512792014-04-22 10:33:12 -04001792 getchar();
1793
1794 if (test_cursor)
1795 clear_cursors(&dev);
1796
Joonyoung Shim4d760d72015-04-28 11:41:39 +01001797 if (plane_count)
1798 clear_planes(&dev, plane_args, plane_count);
1799
Joonyoung Shim4e4d79d2015-04-13 17:32:14 +09001800 if (count)
1801 clear_mode(&dev);
Jesse Barnes731cd552008-12-17 10:09:49 -08001802 }
1803
Laurent Pinchart549fe0b2013-02-27 05:35:13 +01001804 free_resources(dev.resources);
Jesse Barnes731cd552008-12-17 10:09:49 -08001805
1806 return 0;
1807}