kms_rotation_crc: Remove useless comments
[platform/upstream/intel-gpu-tools.git] / tests / kms_setmode.c
1 /*
2  * Permission is hereby granted, free of charge, to any person obtaining a
3  * copy of this software and associated documentation files (the "Software"),
4  * to deal in the Software without restriction, including without limitation
5  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6  * and/or sell copies of the Software, and to permit persons to whom the
7  * Software is furnished to do so, subject to the following conditions:
8  *
9  * The above copyright notice and this permission notice shall be included in
10  * all copies or substantial portions of the Software.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18  * IN THE SOFTWARE.
19  *
20  * Authors:
21  *    Imre Deak <imre.deak@intel.com>
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <cairo.h>
28 #include <errno.h>
29 #include <stdint.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <sys/time.h>
34
35 #include "drmtest.h"
36 #include "intel_bufmgr.h"
37 #include "intel_batchbuffer.h"
38 #include "intel_io.h"
39 #include "igt_kms.h"
40
41 #define MAX_CONNECTORS  10
42 #define MAX_CRTCS       3
43
44 /* max combinations with repetitions */
45 #define MAX_COMBINATION_COUNT   \
46         (MAX_CONNECTORS * MAX_CONNECTORS * MAX_CONNECTORS)
47 #define MAX_COMBINATION_ELEMS   MAX_CRTCS
48
49 static int drm_fd;
50 static drmModeRes *drm_resources;
51 static int filter_test_id;
52 static bool dry_run;
53
54 const drmModeModeInfo mode_640_480 = {
55         .name           = "640x480",
56         .vrefresh       = 60,
57         .clock          = 25200,
58
59         .hdisplay       = 640,
60         .hsync_start    = 656,
61         .hsync_end      = 752,
62         .htotal         = 800,
63
64         .vdisplay       = 480,
65         .vsync_start    = 490,
66         .vsync_end      = 492,
67         .vtotal         = 525,
68
69         .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
70 };
71
72 enum test_flags {
73         TEST_INVALID                    = 0x01,
74         TEST_CLONE                      = 0x02,
75         TEST_SINGLE_CRTC_CLONE          = 0x04,
76         TEST_EXCLUSIVE_CRTC_CLONE       = 0x08,
77 };
78
79 struct test_config {
80         const char *name;
81         enum test_flags flags;
82         drmModeRes *resources;
83 };
84
85 struct connector_config {
86         drmModeConnector *connector;
87         int crtc_idx;
88         bool connected;
89         drmModeModeInfo default_mode;
90 };
91
92 struct crtc_config {
93         int crtc_idx;
94         int crtc_id;
95         int pipe_id;
96         int connector_count;
97         struct connector_config *cconfs;
98         struct igt_fb fb_info;
99         drmModeModeInfo mode;
100 };
101
102 static bool drm_mode_equal(drmModeModeInfo *m1, drmModeModeInfo *m2)
103 {
104 #define COMP(x) do { if (m1->x != m2->x) return false; } while (0)
105         COMP(vrefresh);
106         COMP(clock);
107         COMP(hdisplay);
108         COMP(hsync_start);
109         COMP(hsync_end);
110         COMP(htotal);
111         COMP(vdisplay);
112         COMP(vsync_start);
113         COMP(vsync_end);
114         COMP(vtotal);
115         COMP(flags);
116
117         return true;
118 }
119
120 static bool connector_supports_mode(drmModeConnector *connector,
121                                     drmModeModeInfo *mode)
122 {
123         int i;
124
125         for (i = 0; i < connector->count_modes; i++)
126                 if (drm_mode_equal(&connector->modes[i], mode))
127                         return true;
128
129         return false;
130 }
131
132 static bool crtc_supports_mode(struct crtc_config *crtc, drmModeModeInfo *mode)
133 {
134         int i;
135
136         for (i = 0; i < crtc->connector_count; i++) {
137                 if (!connector_supports_mode(crtc->cconfs[i].connector, mode))
138                         return false;
139         }
140
141         return true;
142 }
143
144 static int paint_fb(struct igt_fb *fb, const char *test_name,
145                     const char **crtc_str, int crtc_count, int current_crtc_idx)
146 {
147         double x, y;
148         cairo_t *cr;
149         int i;
150
151         cr = igt_get_cairo_ctx(drm_fd, fb);
152
153         igt_paint_test_pattern(cr, fb->width, fb->height);
154
155         cairo_move_to(cr, fb->width / 2, fb->height / 2);
156         cairo_set_font_size(cr, 24);
157         igt_cairo_printf_line(cr, align_hcenter, 40, "%s", test_name);
158
159         cairo_get_current_point(cr, &x, &y);
160         cairo_move_to(cr, 60, y);
161
162         for (i = 0; i < crtc_count; i++) {
163                 if (i == current_crtc_idx) {
164                         cairo_get_current_point(cr, &x, &y);
165                         cairo_move_to(cr, x - 20, y);
166                         igt_cairo_printf_line(cr, align_right, 20, "X");
167                         cairo_move_to(cr, x, y);
168                 }
169                 igt_cairo_printf_line(cr, align_left, 20, "%s",
170                                           crtc_str[i]);
171         }
172
173         cairo_destroy(cr);
174
175         return 0;
176 }
177
178 static void create_fb_for_crtc(struct crtc_config *crtc,
179                                struct igt_fb *fb_info)
180 {
181         int bpp;
182         int depth;
183         bool enable_tiling;
184         int fb_id;
185
186         bpp = 32;
187         depth = 24;
188         enable_tiling = false;
189         fb_id = igt_create_fb(drm_fd, crtc->mode.hdisplay,
190                                   crtc->mode.vdisplay,
191                                   igt_bpp_depth_to_drm_format(bpp, depth),
192                                   enable_tiling, fb_info);
193         igt_assert(fb_id > 0);
194 }
195
196 static void get_mode_for_crtc(struct crtc_config *crtc,
197                               drmModeModeInfo *mode_ret)
198 {
199         drmModeModeInfo mode;
200         int i;
201
202         /*
203          * First try to select a default mode that is supported by all
204          * connectors.
205          */
206         for (i = 0; i < crtc->connector_count; i++) {
207                 mode = crtc->cconfs[i].default_mode;
208                 if (crtc_supports_mode(crtc, &mode))
209                         goto found;
210         }
211
212         /*
213          * Then just fall back to find any that is supported by all
214          * connectors.
215          */
216         for (i = 0; i < crtc->cconfs[0].connector->count_modes; i++) {
217                 mode = crtc->cconfs[0].connector->modes[i];
218                 if (crtc_supports_mode(crtc, &mode))
219                         goto found;
220         }
221
222         /*
223          * If none is found then just pick the default mode of the first
224          * connector and hope the other connectors can support it by scaling
225          * etc.
226          */
227         mode = crtc->cconfs[0].default_mode;
228 found:
229         *mode_ret = mode;
230 }
231
232 static int get_encoder_idx(drmModeRes *resources, drmModeEncoder *encoder)
233 {
234         int i;
235
236         for (i = 0; i < resources->count_encoders; i++)
237                 if (resources->encoders[i] == encoder->encoder_id)
238                         return i;
239         igt_assert(0);
240 }
241
242 static void get_crtc_config_str(struct crtc_config *crtc, char *buf,
243                                 size_t buf_size)
244 {
245         int pos;
246         int i;
247
248         pos = snprintf(buf, buf_size,
249                        "CRTC[%d] [Pipe %s] Mode: %s@%dHz Connectors: ",
250                        crtc->crtc_id, kmstest_pipe_str(crtc->pipe_id),
251                        crtc->mode.name, crtc->mode.vrefresh);
252         if (pos > buf_size)
253                 return;
254         for (i = 0; i < crtc->connector_count; i++) {
255                 drmModeConnector *connector = crtc->cconfs[i].connector;
256
257                 pos += snprintf(&buf[pos], buf_size - pos,
258                         "%s%s-%d[%d]%s", i ? ", " : "",
259                         kmstest_connector_type_str(connector->connector_type),
260                         connector->connector_type_id, connector->connector_id,
261                         crtc->cconfs[i].connected ? "" : " (NC)");
262                 if (pos > buf_size)
263                         return;
264         }
265 }
266
267 static void setup_crtcs(drmModeRes *resources, struct connector_config *cconf,
268                         int connector_count, struct crtc_config *crtcs,
269                         int *crtc_count_ret, bool *config_valid_ret)
270 {
271         struct crtc_config *crtc;
272         int crtc_count;
273         bool config_valid;
274         int i;
275         int encoder_usage_count[resources->count_encoders];
276
277         i = 0;
278         crtc_count = 0;
279         crtc = crtcs;
280         config_valid = true;
281
282         while (i < connector_count) {
283                 drmModeCrtc *drm_crtc;
284                 unsigned long encoder_mask;
285                 int j;
286
287                 igt_assert(crtc_count < MAX_CRTCS);
288
289                 crtc->crtc_idx = cconf[i].crtc_idx;
290                 drm_crtc = drmModeGetCrtc(drm_fd,
291                                           resources->crtcs[crtc->crtc_idx]);
292                 crtc->crtc_id = drm_crtc->crtc_id;
293                 drmModeFreeCrtc(drm_crtc);
294                 crtc->pipe_id = kmstest_get_pipe_from_crtc_id(drm_fd,
295                                                               crtc->crtc_id);
296
297                 crtc->connector_count = 1;
298                 for (j = i + 1; j < connector_count; j++)
299                         if (cconf[j].crtc_idx == crtc->crtc_idx)
300                                 crtc->connector_count++;
301
302                 crtc->cconfs = malloc(sizeof(*crtc->cconfs) *
303                                       crtc->connector_count);
304                 igt_assert(crtc->cconfs);
305
306                 encoder_mask = 0;
307                 for (j = 0; j < crtc->connector_count; j++) {
308                         drmModeConnector *connector;
309                         drmModeEncoder *encoder;
310
311                         crtc->cconfs[j] = cconf[i + j];
312                         connector = cconf[i + j].connector;
313
314                         /* Intel connectors have only a single encoder */
315                         igt_assert(connector->count_encoders == 1);
316                         encoder = drmModeGetEncoder(drm_fd,
317                                                     connector->encoders[0]);
318                         igt_assert(encoder);
319
320                         config_valid &= !!(encoder->possible_crtcs &
321                                           (1 << crtc->crtc_idx));
322
323                         encoder_mask |= 1 << get_encoder_idx(resources,
324                                                              encoder);
325                         config_valid &= !(encoder_mask &
326                                           ~encoder->possible_clones);
327
328                         drmModeFreeEncoder(encoder);
329                 }
330                 get_mode_for_crtc(crtc, &crtc->mode);
331                 create_fb_for_crtc(crtc, &crtc->fb_info);
332
333                 i += crtc->connector_count;
334                 crtc_count++;
335                 crtc++;
336         }
337
338         memset(encoder_usage_count, 0, sizeof(encoder_usage_count));
339         for (i = 0; i < connector_count; i++) {
340                 drmModeConnector *connector = cconf[i].connector;
341                 drmModeEncoder *encoder;
342
343                 igt_assert(connector->count_encoders == 1);
344                 encoder = drmModeGetEncoder(drm_fd, connector->encoders[0]);
345                 encoder_usage_count[get_encoder_idx(resources, encoder)]++;
346                 drmModeFreeEncoder(encoder);
347         }
348         for (i = 0; i < resources->count_encoders; i++)
349                 if (encoder_usage_count[i] > 1)
350                         config_valid = false;
351
352         *crtc_count_ret = crtc_count;
353         *config_valid_ret = config_valid;
354 }
355
356 static void cleanup_crtcs(struct crtc_config *crtcs, int crtc_count)
357 {
358         int i;
359
360         for (i = 0; i < crtc_count; i++) {
361                 free(crtcs[i].cconfs);
362         }
363 }
364
365 static uint32_t *get_connector_ids(struct crtc_config *crtc)
366 {
367         uint32_t *ids;
368         int i;
369
370         ids = malloc(sizeof(*ids) * crtc->connector_count);
371         igt_assert(ids);
372         for (i = 0; i < crtc->connector_count; i++)
373                 ids[i] = crtc->cconfs[i].connector->connector_id;
374
375         return ids;
376 }
377
378 static void test_crtc_config(const struct test_config *tconf,
379                              struct crtc_config *crtcs, int crtc_count)
380 {
381         char str_buf[MAX_CRTCS][1024];
382         const char *crtc_strs[MAX_CRTCS];
383         struct crtc_config *crtc;
384         static int test_id;
385         bool config_failed = false;
386         bool connector_connected = false;
387         int ret = 0;
388         int i;
389
390         test_id++;
391
392         if (filter_test_id && filter_test_id != test_id)
393                 return;
394
395         igt_info("  Test id#%d CRTC count %d\n", test_id, crtc_count);
396
397         for (i = 0; i < crtc_count; i++) {
398                 get_crtc_config_str(&crtcs[i], str_buf[i], sizeof(str_buf[i]));
399                 crtc_strs[i] = &str_buf[i][0];
400         }
401
402         if (dry_run) {
403                 for (i = 0; i < crtc_count; i++)
404                         igt_info("    %s\n", crtc_strs[i]);
405                 return;
406         }
407
408         for (i = 0; i < crtc_count; i++) {
409                 uint32_t *ids;
410                 int j;
411
412                 crtc = &crtcs[i];
413
414                 igt_info("    %s\n", crtc_strs[i]);
415
416                 create_fb_for_crtc(crtc, &crtc->fb_info);
417                 paint_fb(&crtc->fb_info, tconf->name, crtc_strs, crtc_count, i);
418
419                 ids = get_connector_ids(crtc);
420                 ret = drmModeSetCrtc(drm_fd, crtc->crtc_id,
421                                      crtc->fb_info.fb_id, 0, 0, ids,
422                                      crtc->connector_count, &crtc->mode);
423                 free(ids);
424
425                 if (ret < 0) {
426                         igt_assert(errno == EINVAL);
427                         config_failed = true;
428                 }
429
430                 for (j = 0; j < crtc->connector_count; j++)
431                         connector_connected |= crtc->cconfs[j].connected;
432         }
433
434         igt_assert(config_failed == !!(tconf->flags & TEST_INVALID));
435
436         if (ret == 0 && connector_connected && !(tconf->flags & TEST_INVALID))
437                 sleep(5);
438
439         for (i = 0; i < crtc_count; i++) {
440                 if (crtcs[i].fb_info.fb_id) {
441                         drmModeSetCrtc(drm_fd, crtcs[i].crtc_id, 0, 0, 0, NULL,
442                                         0, NULL);
443                         drmModeRmFB(drm_fd, crtcs[i].fb_info.fb_id);
444                         crtcs[i].fb_info.fb_id = 0;
445                 }
446         }
447
448         return;
449 }
450
451 static void test_one_combination(const struct test_config *tconf,
452                                  struct connector_config *cconfs,
453                                  int connector_count)
454 {
455         struct crtc_config crtcs[MAX_CRTCS];
456         int crtc_count;
457         bool config_valid;
458
459         setup_crtcs(tconf->resources, cconfs, connector_count, crtcs,
460                     &crtc_count, &config_valid);
461
462         if (config_valid == !(tconf->flags & TEST_INVALID))
463                 test_crtc_config(tconf, crtcs, crtc_count);
464
465         cleanup_crtcs(crtcs, crtc_count);
466 }
467
468 static int assign_crtc_to_connectors(const struct test_config *tconf,
469                                      int *crtc_idxs, int connector_count,
470                                      struct connector_config *cconfs)
471 {
472         unsigned long crtc_idx_mask;
473         int i;
474
475         crtc_idx_mask = 0;
476         for (i = 0; i < connector_count; i++) {
477                 int crtc_idx = crtc_idxs[i];
478
479                 if ((tconf->flags & TEST_SINGLE_CRTC_CLONE) &&
480                     crtc_idx_mask & ~(1 << crtc_idx))
481                         return -1;
482
483                 if ((tconf->flags & TEST_EXCLUSIVE_CRTC_CLONE) &&
484                     crtc_idx_mask & (1 << crtc_idx))
485                         return -1;
486
487                 crtc_idx_mask |= 1 << crtc_idx;
488
489                 cconfs[i].crtc_idx = crtc_idx;
490         }
491
492         return 0;
493 }
494
495 static int get_one_connector(drmModeRes *resources, int connector_id,
496                              struct connector_config *cconf)
497 {
498         drmModeConnector *connector;
499         drmModeModeInfo mode;
500
501         connector = drmModeGetConnector(drm_fd, connector_id);
502         igt_assert(connector);
503         cconf->connector = connector;
504
505         cconf->connected = connector->connection == DRM_MODE_CONNECTED;
506
507         /*
508          * For DP/eDP we need a connected sink, since mode setting depends
509          * on successful link training and retrieved DPCD parameters.
510          */
511         switch (connector->connector_type) {
512         case DRM_MODE_CONNECTOR_DisplayPort:
513         case DRM_MODE_CONNECTOR_eDP:
514                 if (!cconf->connected) {
515                         drmModeFreeConnector(connector);
516                         return -1;
517                 }
518         }
519
520         if (cconf->connected) {
521                 if (kmstest_get_connector_default_mode(drm_fd, connector,
522                                                         &mode) < 0)
523                         mode = mode_640_480;
524         } else {
525                 mode = mode_640_480;
526         }
527
528         cconf->default_mode = mode;
529
530         return 0;
531 }
532
533 static int get_connectors(drmModeRes *resources, int *connector_idxs,
534                           int connector_count, struct connector_config *cconfs)
535 {
536         int i;
537
538         for (i = 0; i < connector_count; i++) {
539                 int connector_idx;
540                 int connector_id;
541
542                 connector_idx = connector_idxs[i];
543                 igt_assert(connector_idx < resources->count_connectors);
544                 connector_id = resources->connectors[connector_idx];
545
546                 if (get_one_connector(resources, connector_id, &cconfs[i]) < 0)
547                         goto err;
548
549         }
550
551         return 0;
552
553 err:
554         while (i--)
555                 drmModeFreeConnector(cconfs[i].connector);
556
557         return -1;
558 }
559
560 static void free_connectors(struct connector_config *cconfs,
561                             int connector_count)
562 {
563         int i;
564
565         for (i = 0; i < connector_count; i++)
566                 drmModeFreeConnector(cconfs[i].connector);
567 }
568
569 struct combination {
570         int elems[MAX_COMBINATION_ELEMS];
571 };
572
573 struct combination_set {
574         int count;
575         struct combination items[MAX_COMBINATION_COUNT];
576 };
577
578 /*
579  * Get all possible selection of k elements from n elements with or without
580  * repetitions.
581  */
582 static void iterate_combinations(int n, int k, bool allow_repetitions,
583                                  int depth, int base, struct combination *comb,
584                                  struct combination_set *set)
585 {
586         int v;
587
588         if (!k) {
589                 igt_assert(set->count < ARRAY_SIZE(set->items));
590                 set->items[set->count++] = *comb;
591                 return;
592         }
593
594         for (v = base; v < n; v++) {
595                 comb->elems[depth] = v;
596                 iterate_combinations(n, k - 1, allow_repetitions,
597                                      depth + 1, allow_repetitions ? 0 : v + 1,
598                                      comb, set);
599         }
600
601 }
602
603 static void get_combinations(int n, int k, bool allow_repetitions,
604                              struct combination_set *set)
605 {
606         struct combination comb;
607
608         igt_assert(k <= ARRAY_SIZE(set->items[0].elems));
609         set->count = 0;
610         iterate_combinations(n, k, allow_repetitions, 0, 0, &comb, set);
611 }
612
613 static void test_combinations(const struct test_config *tconf,
614                               int connector_count)
615 {
616         struct combination_set connector_combs;
617         struct combination_set crtc_combs;
618         struct connector_config *cconfs;
619         int i;
620
621         get_combinations(tconf->resources->count_connectors, connector_count,
622                          false, &connector_combs);
623         get_combinations(tconf->resources->count_crtcs, connector_count,
624                          true, &crtc_combs);
625
626         igt_info("Testing: %s %d connector combinations\n", tconf->name,
627                  connector_count);
628         for (i = 0; i < connector_combs.count; i++) {
629                 int *connector_idxs;
630                 int ret;
631                 int j;
632
633                 cconfs = malloc(sizeof(*cconfs) * connector_count);
634                 igt_assert(cconfs);
635
636                 connector_idxs = &connector_combs.items[i].elems[0];
637                 ret = get_connectors(tconf->resources, connector_idxs,
638                                      connector_count, cconfs);
639                 if (ret < 0)
640                         goto free_cconfs;
641
642                 for (j = 0; j < crtc_combs.count; j++) {
643                         int *crtc_idxs = &crtc_combs.items[j].elems[0];
644                         ret = assign_crtc_to_connectors(tconf, crtc_idxs,
645                                                         connector_count,
646                                                         cconfs);
647                         if (ret < 0)
648                                 continue;
649
650                         test_one_combination(tconf, cconfs, connector_count);
651                 }
652
653                 free_connectors(cconfs, connector_count);
654 free_cconfs:
655                 free(cconfs);
656         }
657 }
658
659 static void run_test(const struct test_config *tconf)
660 {
661         int connector_num;
662
663         connector_num = tconf->flags & TEST_CLONE ? 2 : 1;
664         for (; connector_num <= tconf->resources->count_crtcs; connector_num++)
665                 test_combinations(tconf, connector_num);
666 }
667
668 static int opt_handler(int opt, int opt_index)
669 {
670         switch (opt) {
671         case 'd':
672                 dry_run = true;
673                 break;
674         case 't':
675                 filter_test_id = atoi(optarg);
676                 break;
677         default:
678                 igt_assert(0);
679         }
680
681         return 0;
682 }
683
684 int main(int argc, char **argv)
685 {
686         const struct {
687                 enum test_flags flags;
688                 const char *name;
689         } tests[] = {
690                 { TEST_CLONE | TEST_SINGLE_CRTC_CLONE,
691                                         "clone-single-crtc" },
692                 { TEST_INVALID | TEST_CLONE | TEST_SINGLE_CRTC_CLONE,
693                                         "invalid-clone-single-crtc" },
694                 { TEST_INVALID | TEST_CLONE | TEST_EXCLUSIVE_CRTC_CLONE,
695                                         "invalid-clone-exclusive-crtc" },
696                 { TEST_CLONE | TEST_EXCLUSIVE_CRTC_CLONE,
697                                         "clone-exclusive-crtc" },
698         };
699         const char *help_str =
700                "  -d\t\tDon't run any test, only print what would be done. (still needs DRM access)\n"
701                "  -t <test id>\tRun only the test with this id.";
702         int i;
703         int ret;
704
705         ret = igt_subtest_init_parse_opts(argc, argv, "dt:", NULL, help_str,
706                                           opt_handler);
707         if (ret < 0)
708                 return ret == -1 ? 0 : ret;
709
710         igt_skip_on_simulation();
711
712         igt_assert_f(!(dry_run && filter_test_id),
713                      "only one of -d and -t is accepted\n");
714
715         igt_fixture {
716                 drm_fd = drm_open_any();
717                 if (!dry_run)
718                         igt_set_vt_graphics_mode();
719
720                 drm_resources = drmModeGetResources(drm_fd);
721                 igt_assert(drm_resources);
722         }
723
724         for (i = 0; i < ARRAY_SIZE(tests); i++) {
725                 igt_subtest(tests[i].name) {
726                         struct test_config tconf = {
727                                 .flags          = tests[i].flags,
728                                 .name           = tests[i].name,
729                                 .resources      = drm_resources,
730                         };
731                         run_test(&tconf);
732                 }
733         }
734
735         igt_fixture {
736                 drmModeFreeResources(drm_resources);
737
738                 close(drm_fd);
739         }
740
741         igt_exit();
742 }