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