1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Displayport Compliance Testing Application
24 *
25 * This is the userspace component of the Displayport Compliance testing
26 * software required for compliance testing of the I915 Display Port driver.
27 * This must be running in order to successfully complete Display Port
28 * compliance testing. This app and the kernel code that accompanies it has been
29 * written to satify the requirements of the Displayport Link CTS 1.2 rev1.1
30 * specification from VESA. Note that this application does not support eDP
31 * compliance testing.
32 *
33 * Compliance Testing requires several components:
34 * - A kernel build that contains the patch set for DP compliance support
35 * - A Displayport Compliance Testing appliance such as Unigraf-DPR120
36 * - This user application
37 * - A windows host machine to run the DPR test software
38 * - Root access on the DUT due to the use of sysfs utility
39 *
40 * Test Setup:
41 * It is strongly recommended that the windows host, test appliance and DUT
42 * be freshly restarted before any testing begins to ensure that any previous
43 * configurations and settings will not interfere with test process. Refer to
44 * the test appliance documentation for setup, software installation and
45 * operation specific to that device.
46 *
47 * The Linux DUT must be in text (console) mode and cannot have any other
48 * display manager running. You must be logged in as root to run this user app.
49 * Once the user application is up and running, waiting for test requests, the
50 * software on the windows host can now be used to execute the compliance tests.
51 *
52 * This userspace application supports following tests from the DP CTS Spec
53 * Rev 1.1:
54 * - Link Training Tests: Supports tests 4.3.1.1 to 4.3.2.3
55 * - EDID Tests: Supports EDID read (4.2.2.3),EDID Read failure and corruption
56 * detection tests (4.2.2.4, 4.2.2.5, 4.2.2.6)
57 * - Video Pattern generation tests: This supports only the 24 and 18bpp color
58 * ramp test pattern (4.3.3.1).
59 *
60 * Connections (required):
61 * - Test Appliance connected to the external Displayport connector on the DUT
62 * - Test Appliance Monitor Out connected to Displayport connector on the
63 * monitor
64 * - Test appliance connected to the Windows Host via USB
65 *
66 * Debugfs Files:
67 * The file root for all the debugfs file:
68 * /sys/kernel/debug/dri/0/
69 *
70 * The specific files are as follows:
71 *
72 * i915_dp_test_active
73 * A simple flag that indicates whether or not compliance testing is currently
74 * active in the kernel. This flag is polled by userspace and once set, invokes
75 * the test handler in the user app. This flag is set by the test handler in the
76 * kernel after reading the registers requested by the test appliance.
77 *
78 * i915_dp_test_data
79 * Test data is used by the kernel to pass parameters to the user app. Eg: In
80 * case of EDID tests, the data that is delivered to the userspace is the video
81 * mode to be set for the test.
82 * In case of video pattern test, the data that is delivered to the userspace is
83 * the width and height of the test pattern and the bits per color value.
84 *
85 * i915_dp_test_type
86 * The test type variable instructs the user app as to what the requested test
87 * was from the sink device. These values defined at the top of the application's
88 * main implementation file must be kept in sync with the values defined in the
89 * kernel's drm_dp_helper.h file.
90 * This app is based on some prior work submitted in April 2015 by Todd Previte
91 * (<tprevite@gmail.com>)
92 *
93 *
94 * This tool can be run as:
95 * ./intel_dp_compliance It will wait till you start compliance suite from
96 * DPR 120.
97 * ./intel_dp_compliance -h This will open the help
98 * ./intel_dp_compliance -i This will provide information about current
99 * connectors/CRTCs. This can be used for debugging purpose.
100 *
101 * Authors:
102 * Manasi Navare <manasi.d.navare@intel.com>
103 *
104 * Elements of the modeset code adapted from David Herrmann's
105 * DRM modeset example
106 *
107 */
108 #include "igt.h"
109 #include <errno.h>
110 #include <getopt.h>
111 #include <math.h>
112 #include <stdint.h>
113 #include <stdbool.h>
114 #include <strings.h>
115 #include <unistd.h>
116 #include <termios.h>
117 #include <sys/poll.h>
118 #include <sys/time.h>
119 #include <sys/ioctl.h>
120 #include <sys/types.h>
121 #include <sys/stat.h>
122 #include <sys/select.h>
123 #include <assert.h>
124 #include <signal.h>
125 #include <fcntl.h>
126 #include <time.h>
127
128 #include "intel_dp_compliance.h"
129
130 #include <stdlib.h>
131 #include <signal.h>
132
133 /* User Input definitions */
134 #define HELP_DESCRIPTION 1
135
136 /* Debugfs file definitions */
137 #define INTEL_DP_TEST_TYPE_FILE "i915_dp_test_type"
138 #define INTEL_DP_TEST_ACTIVE_FILE "i915_dp_test_active"
139 #define INTEL_DP_TEST_DATA_FILE "i915_dp_test_data"
140
141 /* DRM definitions - must be kept in sync with the DRM header */
142 #define DP_TEST_LINK_TRAINING (1 << 0)
143 #define DP_TEST_LINK_VIDEO_PATTERN (1 << 1)
144 #define DP_TEST_LINK_EDID_READ (1 << 2)
145 #define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */
146
147 #define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING | \
148 DP_TEST_LINK_VIDEO_PATTERN | \
149 DP_TEST_LINK_EDID_READ | \
150 DP_TEST_LINK_PHY_TEST_PATTERN)
151
152 /* NOTE: These must be kept in sync with the definitions in intel_dp.c */
153 #define INTEL_DP_EDID_SHIFT_MASK 0
154 #define INTEL_DP_EDID_OK (0 << INTEL_DP_EDID_SHIFT_MASK)
155 #define INTEL_DP_EDID_CORRUPT (1 << INTEL_DP_EDID_SHIFT_MASK)
156 #define INTEL_DP_RESOLUTION_SHIFT_MASK 0
157 #define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
158 #define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK)
159 #define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK)
160 #define DP_COMPLIANCE_VIDEO_MODE_MASK (INTEL_DP_RESOLUTION_PREFERRED |\
161 INTEL_DP_RESOLUTION_STANDARD |\
162 INTEL_DP_RESOLUTION_FAILSAFE)
163
164 /* Global file pointers for the sysfs files */
165 FILE *test_active_fp, *test_data_fp, *test_type_fp;
166
167 bool video_pattern_flag;
168
169 /* Video pattern test globals */
170 uint16_t hdisplay;
171 uint16_t vdisplay;
172 uint8_t bitdepth;
173
174 static int tio_fd;
175 struct termios saved_tio;
176
177 drmModeRes *resources;
178 int drm_fd, modes, gen;
179 uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE;
180 uint32_t depth = 24, stride, bpp;
181 int specified_mode_num = -1, specified_disp_id = -1;
182 int width, height;
183 uint32_t test_crtc;
184 uint32_t test_connector_id;
185 enum {
186 INTEL_MODE_INVALID = -1,
187 INTEL_MODE_NONE = 0,
188 INTEL_MODE_PREFERRED,
189 INTEL_MODE_STANDARD,
190 INTEL_MODE_FAILSAFE,
191 INTEL_MODE_VIDEO_PATTERN_TEST
192 } intel_display_mode;
193
194 struct test_video_pattern {
195 uint16_t hdisplay;
196 uint16_t vdisplay;
197 uint8_t bitdepth;
198 uint32_t fb;
199 uint32_t size;
200 struct igt_fb fb_pattern;
201 drmModeModeInfo mode;
202 uint32_t *pixmap;
203 };
204
205 struct connector {
206 uint32_t id;
207 int mode_valid;
208 drmModeModeInfo mode, mode_standard, mode_preferred, mode_failsafe;
209 drmModeConnector *connector;
210 int crtc;
211 /* Standard and preferred frame buffer*/
212 uint32_t fb, fb_width, fb_height, fb_size;
213 uint8_t *pixmap;
214 struct igt_fb fb_video_pattern;
215 /* Failsafe framebuffer - note this is a 16-bit buffer */
216 uint32_t failsafe_fb, failsafe_width, failsafe_height;
217 uint32_t failsafe_size;
218 uint8_t *failsafe_pixmap;
219 struct igt_fb fb_failsafe_pattern;
220 struct test_video_pattern test_pattern;
221 };
222
clear_test_active(void)223 static void clear_test_active(void)
224 {
225 rewind(test_active_fp);
226 fprintf(test_active_fp, "%d", 0);
227 fflush(test_active_fp);
228 }
229
fopenat(int dir,const char * name,const char * mode)230 static FILE *fopenat(int dir, const char *name, const char *mode)
231 {
232 int fd = openat(dir, name, O_RDWR);
233 return fdopen(fd, mode);
234 }
235
setup_debugfs_files(void)236 static void setup_debugfs_files(void)
237 {
238 int dir = igt_debugfs_dir(drm_fd);
239
240 test_type_fp = fopenat(dir, INTEL_DP_TEST_TYPE_FILE, "r");
241 igt_require(test_type_fp);
242
243 test_data_fp = fopenat(dir, INTEL_DP_TEST_DATA_FILE, "r");
244 igt_require(test_data_fp);
245
246 test_active_fp = fopenat(dir, INTEL_DP_TEST_ACTIVE_FILE, "w+");
247 igt_require(test_active_fp);
248
249 close(dir);
250
251 /* Reset the active flag for safety */
252 clear_test_active();
253 }
254
get_test_type(void)255 static unsigned long get_test_type(void)
256 {
257 unsigned long test_type;
258 int ret;
259
260 if (!test_type_fp)
261 fprintf(stderr, "Invalid test_type file\n");
262 rewind(test_type_fp);
263 ret = fscanf(test_type_fp, "%lx", &test_type);
264 if (ret < 1 || test_type <= 0) {
265 igt_warn("test_type read failed - %lx\n", test_type);
266 return 0;
267 }
268
269 return test_type;
270 }
271
get_test_edid_data(void)272 static unsigned long get_test_edid_data(void)
273 {
274 unsigned long test_data;
275 int ret;
276
277 if (!test_data_fp)
278 fprintf(stderr, "Invalid test_data file\r\n");
279
280 rewind(test_data_fp);
281 ret = fscanf(test_data_fp, "%lx", &test_data);
282 if (ret < 1 || test_data <= 0) {
283 igt_warn("test_data read failed - %lx\r\n", test_data);
284 return 0;
285 }
286
287 return test_data;
288 }
289
get_test_videopattern_data(void)290 static void get_test_videopattern_data(void)
291 {
292 int count = 0;
293 uint16_t video_pattern_value[3];
294 char video_pattern_attribute[15];
295 int ret;
296
297 if (!test_data_fp)
298 fprintf(stderr, "Invalid test_data file\n");
299
300 rewind(test_data_fp);
301 while (!feof(test_data_fp) && count < 3) {
302 ret = fscanf(test_data_fp, "%s %u\n", video_pattern_attribute,
303 (unsigned int *)&video_pattern_value[count++]);
304 if (ret < 2) {
305 igt_warn("test_data read failed\n");
306 return;
307 }
308 }
309
310 hdisplay = video_pattern_value[0];
311 vdisplay = video_pattern_value[1];
312 bitdepth = video_pattern_value[2];
313 igt_info("Hdisplay = %d\n", hdisplay);
314 igt_info("Vdisplay = %d\n", vdisplay);
315 igt_info("BitDepth = %u\n", bitdepth);
316
317 }
318
process_test_request(int test_type)319 static int process_test_request(int test_type)
320 {
321 int mode;
322 unsigned long test_data_edid;
323 bool valid = false;
324 switch (test_type) {
325 case DP_TEST_LINK_VIDEO_PATTERN:
326 video_pattern_flag = true;
327 get_test_videopattern_data();
328 mode = INTEL_MODE_VIDEO_PATTERN_TEST;
329 valid = true;
330 break;
331 case DP_TEST_LINK_EDID_READ:
332 test_data_edid = get_test_edid_data();
333 mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >>
334 INTEL_DP_RESOLUTION_SHIFT_MASK;
335 valid = true;
336 break;
337 default:
338 /* Unknown test type */
339 fprintf(stderr, "Invalid test request, ignored.\n");
340 break;
341 }
342
343 if (valid)
344 return update_display(mode, true);
345
346 return -1;
347 }
348
dump_connectors_fd(int drmfd)349 static void dump_connectors_fd(int drmfd)
350 {
351 int i, j;
352
353 drmModeRes *mode_resources = drmModeGetResources(drmfd);
354
355 if (!mode_resources) {
356 igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
357 return;
358 }
359
360 igt_info("Connectors:\n");
361 igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
362 for (i = 0; i < mode_resources->count_connectors; i++) {
363 drmModeConnector *connector;
364
365 connector = drmModeGetConnectorCurrent(drmfd,
366 mode_resources->connectors[i]);
367 if (!connector) {
368 igt_warn("Could not get connector %i: %s\n",
369 mode_resources->connectors[i], strerror(errno));
370 continue;
371 }
372
373 igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
374 connector->connector_id,
375 connector->encoder_id,
376 kmstest_connector_status_str(connector->connection),
377 kmstest_connector_type_str(connector->connector_type),
378 connector->mmWidth,
379 connector->mmHeight,
380 connector->count_modes);
381
382 if (!connector->count_modes)
383 continue;
384
385 igt_info(" Modes:\n");
386 igt_info(" name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n");
387 for (j = 0; j < connector->count_modes; j++) {
388 igt_info("[%d]", j);
389 kmstest_dump_mode(&connector->modes[j]);
390 }
391
392 drmModeFreeConnector(connector);
393 }
394 igt_info("\n");
395
396 drmModeFreeResources(mode_resources);
397 }
398
dump_crtcs_fd(int drmfd)399 static void dump_crtcs_fd(int drmfd)
400 {
401 int i;
402 drmModeRes *mode_resources;
403
404 mode_resources = drmModeGetResources(drmfd);
405 if (!mode_resources) {
406 igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
407 return;
408 }
409
410 igt_info("CRTCs:\n");
411 igt_info("id\tfb\tpos\tsize\n");
412 for (i = 0; i < mode_resources->count_crtcs; i++) {
413 drmModeCrtc *crtc;
414
415 crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]);
416 if (!crtc) {
417 igt_warn("Could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno));
418 continue;
419 }
420 igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n",
421 crtc->crtc_id,
422 crtc->buffer_id,
423 crtc->x,
424 crtc->y,
425 crtc->width,
426 crtc->height);
427
428 kmstest_dump_mode(&crtc->mode);
429
430 drmModeFreeCrtc(crtc);
431 }
432 igt_info("\n");
433
434 drmModeFreeResources(mode_resources);
435 }
436
dump_info(void)437 static void dump_info(void)
438 {
439 dump_connectors_fd(drm_fd);
440 dump_crtcs_fd(drm_fd);
441 }
442
setup_framebuffers(struct connector * dp_conn)443 static int setup_framebuffers(struct connector *dp_conn)
444 {
445
446 dp_conn->fb = igt_create_fb(drm_fd,
447 dp_conn->fb_width, dp_conn->fb_height,
448 DRM_FORMAT_XRGB8888,
449 LOCAL_DRM_FORMAT_MOD_NONE,
450 &dp_conn->fb_video_pattern);
451 igt_assert(dp_conn->fb);
452
453 /* Map the mapping of GEM object into the virtual address space */
454 dp_conn->pixmap = gem_mmap__gtt(drm_fd,
455 dp_conn->fb_video_pattern.gem_handle,
456 dp_conn->fb_video_pattern.size,
457 PROT_READ | PROT_WRITE);
458 if (dp_conn->pixmap == NULL)
459 return -1;
460
461 gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle,
462 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
463 dp_conn->fb_size = dp_conn->fb_video_pattern.size;
464
465 /* After filling the device memory with 0s it needs to be unmapped */
466 memset(dp_conn->pixmap, 0, dp_conn->fb_size);
467 munmap(dp_conn->pixmap, dp_conn->fb_size);
468
469 return 0;
470 }
471
setup_failsafe_framebuffer(struct connector * dp_conn)472 static int setup_failsafe_framebuffer(struct connector *dp_conn)
473 {
474
475 dp_conn->failsafe_fb = igt_create_fb(drm_fd,
476 dp_conn->failsafe_width,
477 dp_conn->failsafe_height,
478 DRM_FORMAT_XRGB8888,
479 LOCAL_DRM_FORMAT_MOD_NONE,
480 &dp_conn->fb_failsafe_pattern);
481 igt_assert(dp_conn->failsafe_fb);
482
483 /* Map the mapping of GEM object into the virtual address space */
484 dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd,
485 dp_conn->fb_failsafe_pattern.gem_handle,
486 dp_conn->fb_failsafe_pattern.size,
487 PROT_READ | PROT_WRITE);
488 if (dp_conn->failsafe_pixmap == NULL)
489 return -1;
490
491 gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle,
492 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
493 dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size;
494
495 /* After filling the device framebuffer the mapped memory needs to be freed */
496 memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size);
497 munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size);
498
499 return 0;
500
501 }
502
setup_video_pattern_framebuffer(struct connector * dp_conn)503 static int setup_video_pattern_framebuffer(struct connector *dp_conn)
504 {
505 uint32_t video_width, video_height;
506
507 video_width = dp_conn->test_pattern.hdisplay;
508 video_height = dp_conn->test_pattern.vdisplay;
509 /*
510 * Display WA1172: Gen10 To pass the color data unaffected set either
511 * per-pixel alpha or Plane alpha to 0xff. Use ARGB8888 and set alpha to 0xff.
512 */
513 dp_conn->test_pattern.fb = igt_create_fb(drm_fd,
514 video_width, video_height,
515 gen == 10 ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888,
516 LOCAL_DRM_FORMAT_MOD_NONE,
517 &dp_conn->test_pattern.fb_pattern);
518 igt_assert(dp_conn->test_pattern.fb);
519
520 /* Map the mapping of GEM object into the virtual address space */
521 dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd,
522 dp_conn->test_pattern.fb_pattern.gem_handle,
523 dp_conn->test_pattern.fb_pattern.size,
524 PROT_READ | PROT_WRITE);
525 if (dp_conn->test_pattern.pixmap == NULL)
526 return -1;
527
528 gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle,
529 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
530
531 dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size;
532
533 memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size);
534 return 0;
535
536 }
537
fill_framebuffer(struct connector * dp_conn)538 static int fill_framebuffer(struct connector *dp_conn)
539 {
540 uint32_t tile_height, tile_width, video_width, video_height;
541 uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr;
542 int x, y;
543 int32_t pixel_val;
544 uint8_t alpha;
545
546 video_width = dp_conn->test_pattern.hdisplay;
547 video_height = dp_conn->test_pattern.vdisplay;
548
549 tile_height = 64;
550 tile_width = 1 << (dp_conn->test_pattern.bitdepth);
551
552 red_ptr = dp_conn->test_pattern.pixmap;
553 green_ptr = red_ptr + (video_width * tile_height);
554 blue_ptr = green_ptr + (video_width * tile_height);
555 white_ptr = blue_ptr + (video_width * tile_height);
556 x = 0;
557
558 /* Fill the frame buffer with video pattern from CTS 3.1.5 */
559 while (x < video_width) {
560 for (pixel_val = 0; pixel_val < 256;
561 pixel_val = pixel_val + (256 / tile_width)) {
562 alpha = gen == 10 ? 0xff : 0;
563 red_ptr[x] = alpha << 24 | pixel_val << 16;
564 green_ptr[x] = alpha << 24 | pixel_val << 8;
565 blue_ptr[x] = alpha << 24 | pixel_val << 0;
566 white_ptr[x] = alpha << 24 | red_ptr[x] | green_ptr[x] |
567 blue_ptr[x];
568 if (++x >= video_width)
569 break;
570 }
571 }
572 for (y = 0; y < video_height; y++) {
573 if (y == 0 || y == 64 || y == 128 || y == 192)
574 continue;
575 switch ((y / tile_height) % 4) {
576 case 0:
577 src_ptr = red_ptr;
578 break;
579 case 1:
580 src_ptr = green_ptr;
581 break;
582 case 2:
583 src_ptr = blue_ptr;
584 break;
585 case 3:
586 src_ptr = white_ptr;
587 break;
588 }
589 dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width);
590 memcpy(dst_ptr, src_ptr, (video_width * 4));
591 }
592 munmap(dp_conn->test_pattern.pixmap,
593 dp_conn->test_pattern.size);
594 return 0;
595 }
596
set_test_mode(struct connector * dp_conn)597 static int set_test_mode(struct connector *dp_conn)
598 {
599 int ret = 0;
600 int i;
601 bool found_std = false, found_fs = false;
602 drmModeConnector *c = dp_conn->connector;
603
604 /* Ignore any disconnected devices */
605 if (c->connection != DRM_MODE_CONNECTED) {
606 igt_warn("Connector %u disconnected\n", c->connector_id);
607 return -ENOENT;
608 }
609 igt_info("Connector setup:\n");
610 /* Setup preferred mode - should be mode[0] in the list */
611 dp_conn->mode_preferred = c->modes[0];
612 dp_conn->fb_width = c->modes[0].hdisplay;
613 dp_conn->fb_height = c->modes[0].vdisplay;
614
615 dp_conn->test_pattern.mode = c->modes[0];
616 dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay;
617 dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay;
618
619 igt_info("Preferred mode (mode 0) for connector %u is %ux%u\n",
620 dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay);
621 fflush(stdin);
622
623 for (i = 1; i < c->count_modes; i++) {
624 /* Standard mode is 800x600@60 */
625 if (c->modes[i].hdisplay == 800 &&
626 c->modes[i].vdisplay == 600 &&
627 c->modes[i].vrefresh == 60 &&
628 found_std == false) {
629 dp_conn->mode_standard = c->modes[i];
630 igt_info("Standard mode (%d) for connector %u is %ux%u\n",
631 i,
632 c->connector_id,
633 c->modes[i].hdisplay,
634 c->modes[i].vdisplay);
635 found_std = true;
636 }
637 /* Failsafe mode is 640x480@60 */
638 if (c->modes[i].hdisplay == 640 &&
639 c->modes[i].vdisplay == 480 &&
640 c->modes[i].vrefresh == 60 &&
641 found_fs == false) {
642 dp_conn->mode_failsafe = c->modes[i];
643 dp_conn->failsafe_width = c->modes[i].hdisplay;
644 dp_conn->failsafe_height = c->modes[i].vdisplay;
645 igt_info("Failsafe mode (%d) for connector %u is %ux%u\n",
646 i,
647 c->connector_id,
648 c->modes[i].hdisplay,
649 c->modes[i].vdisplay);
650 found_fs = true;
651 }
652 }
653
654 ret = setup_framebuffers(dp_conn);
655 if (ret) {
656 igt_warn("Creating framebuffer for connector %u failed (%d)\n",
657 c->connector_id, ret);
658 return ret;
659 }
660
661 if (found_fs) {
662 ret = setup_failsafe_framebuffer(dp_conn);
663 if (ret) {
664 igt_warn("Creating failsafe framebuffer for connector %u failed (%d)\n",
665 c->connector_id, ret);
666 return ret;
667 }
668 }
669
670 if (video_pattern_flag) {
671 dp_conn->test_pattern.hdisplay = hdisplay;
672 dp_conn->test_pattern.vdisplay = vdisplay;
673 dp_conn->test_pattern.bitdepth = bitdepth;
674
675 ret = setup_video_pattern_framebuffer(dp_conn);
676 if (ret) {
677 igt_warn("Creating framebuffer for connector %u failed (%d)\n",
678 c->connector_id, ret);
679 return ret;
680 }
681
682 ret = fill_framebuffer(dp_conn);
683 if (ret) {
684 igt_warn("Filling framebuffer for connector %u failed (%d)\n",
685 c->connector_id, ret);
686 return ret;
687 }
688 }
689
690 return ret;
691 }
692
set_video(int mode,struct connector * test_connector)693 static int set_video(int mode, struct connector *test_connector)
694 {
695 drmModeModeInfo *requested_mode;
696 uint32_t required_fb_id;
697 struct igt_fb required_fb;
698 int ret = 0;
699
700 switch (mode) {
701 case INTEL_MODE_NONE:
702 igt_info("NONE\n");
703 ret = drmModeSetCrtc(drm_fd, test_connector->crtc,
704 -1, 0, 0, NULL, 0, NULL);
705 goto out;
706 case INTEL_MODE_PREFERRED:
707 igt_info("PREFERRED\n");
708 requested_mode = &test_connector->mode_preferred;
709 required_fb_id = test_connector->fb;
710 required_fb = test_connector->fb_video_pattern;
711 break;
712 case INTEL_MODE_STANDARD:
713 igt_info("STANDARD\n");
714 requested_mode = &test_connector->mode_standard;
715 required_fb_id = test_connector->fb;
716 required_fb = test_connector->fb_video_pattern;
717 break;
718 case INTEL_MODE_FAILSAFE:
719 igt_info("FAILSAFE\n");
720 requested_mode = &test_connector->mode_failsafe;
721 required_fb_id = test_connector->failsafe_fb;
722 required_fb = test_connector->fb_failsafe_pattern;
723 break;
724 case INTEL_MODE_VIDEO_PATTERN_TEST:
725 igt_info("VIDEO PATTERN TEST\n");
726 requested_mode = &test_connector->test_pattern.mode;
727 required_fb_id = test_connector->test_pattern.fb;
728 required_fb = test_connector->test_pattern.fb_pattern;
729 break;
730 case INTEL_MODE_INVALID:
731 default:
732 igt_warn("INVALID! (%08x) Mode set aborted!\n", mode);
733 return -1;
734 }
735
736 igt_info("CRTC(%u):", test_connector->crtc);
737 kmstest_dump_mode(requested_mode);
738 ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0,
739 &test_connector->id, 1, requested_mode);
740 if (ret) {
741 igt_warn("Failed to set mode (%dx%d@%dHz): %s\n",
742 requested_mode->hdisplay, requested_mode->vdisplay,
743 requested_mode->vrefresh, strerror(errno));
744 igt_remove_fb(drm_fd, &required_fb);
745
746 }
747 /* Keep the pattern on output lines for 1 sec for DPR-120 to detect it */
748 sleep(1);
749
750 out:
751 if (ret) {
752 igt_warn("Failed to set CRTC for connector %u\n",
753 test_connector->id);
754 }
755
756 return ret;
757 }
758
759 static int
set_default_mode(struct connector * c,bool set_mode)760 set_default_mode(struct connector *c, bool set_mode)
761 {
762 unsigned int fb_id = 0;
763 struct igt_fb fb_info;
764 int ret = 0;
765
766 if (!set_mode) {
767 ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0,
768 NULL, 0, NULL);
769 if (ret)
770 igt_warn("Failed to unset mode");
771 return ret;
772 }
773
774 c->mode = c->connector->modes[0];
775
776 width = c->mode.hdisplay;
777 height = c->mode.vdisplay;
778
779 fb_id = igt_create_pattern_fb(drm_fd, width, height,
780 DRM_FORMAT_XRGB8888,
781 tiling, &fb_info);
782
783 igt_info("CRTC(%u):[%d]", c->crtc, 0);
784 kmstest_dump_mode(&c->mode);
785 drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL);
786 ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
787 &c->id, 1, &c->mode);
788 if (ret) {
789 igt_warn("Failed to set mode (%dx%d@%dHz): %s\n",
790 width, height, c->mode.vrefresh, strerror(errno));
791 igt_remove_fb(drm_fd, &fb_info);
792
793 }
794
795 return ret;
796 }
797
find_crtc_for_connector(drmModeConnector * c)798 static uint32_t find_crtc_for_connector(drmModeConnector *c)
799 {
800 drmModeEncoder *e;
801 uint32_t possible_crtcs;
802 int i, j;
803
804 for (i = 0; i < c->count_encoders; i++) {
805 e = drmModeGetEncoder(drm_fd, c->encoders[i]);
806 possible_crtcs = e->possible_crtcs;
807 drmModeFreeEncoder(e);
808
809 for (j = 0; possible_crtcs >> j; j++)
810 if (possible_crtcs & (1 << j))
811 return resources->crtcs[j];
812 }
813 return 0;
814 }
815
816 /*
817 * Re-probe connectors and do a modeset based on test request or
818 * in case of a hotplug uevent.
819 *
820 * @mode: Video mode requested by the test
821 * @is_compliance_test: 1: If it is a compliance test
822 * 0: If it is a hotplug event
823 *
824 * Returns:
825 * 0: On Success
826 * -1: On failure
827 */
update_display(int mode,bool is_compliance_test)828 int update_display(int mode, bool is_compliance_test)
829 {
830 struct connector *connectors, *conn;
831 int cnt, ret = 0;
832 bool set_mode;
833
834 resources = drmModeGetResources(drm_fd);
835 if (!resources) {
836 igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
837 return -1;
838 }
839
840 connectors = calloc(resources->count_connectors,
841 sizeof(struct connector));
842 if (!connectors)
843 return -1;
844
845 /* Find any connected displays */
846 for (cnt = 0; cnt < resources->count_connectors; cnt++) {
847 drmModeConnector *c;
848
849 conn = &connectors[cnt];
850 conn->id = resources->connectors[cnt];
851 c = drmModeGetConnector(drm_fd, conn->id);
852 if (c->connector_type == DRM_MODE_CONNECTOR_DisplayPort &&
853 c->connection == DRM_MODE_CONNECTED) {
854 test_connector_id = c->connector_id;
855 conn->connector = c;
856 conn->crtc = find_crtc_for_connector(c);
857 test_crtc = conn->crtc;
858 set_mode = true;
859 break;
860 } else if (c->connector_id == test_connector_id &&
861 c->connection == DRM_MODE_DISCONNECTED) {
862 conn->connector = c;
863 conn->crtc = test_crtc;
864 set_mode = false;
865 break;
866 }
867 }
868
869 if (cnt == resources->count_connectors) {
870 ret = -1;
871 goto err;
872 }
873
874 if (is_compliance_test) {
875 set_test_mode(conn);
876 ret = set_video(INTEL_MODE_NONE, conn);
877 ret = set_video(mode, conn);
878
879 } else
880 ret = set_default_mode(conn, set_mode);
881
882 err:
883 drmModeFreeConnector(conn->connector);
884 /* Error condition if no connected displays */
885 free(connectors);
886 drmModeFreeResources(resources);
887 return ret;
888 }
889
890 static const char optstr[] = "hi";
891
usage(char * name,char opt)892 static void __attribute__((noreturn)) usage(char *name, char opt)
893 {
894 igt_info("usage: %s [-hi]\n", name);
895 igt_info("\t-i\tdump info\n");
896 igt_info("\tDefault is to respond to DPR-120 tests\n");
897 exit((opt != 'h') ? -1 : 0);
898 }
899
cleanup_debugfs(void)900 static void cleanup_debugfs(void)
901 {
902 fclose(test_active_fp);
903 fclose(test_data_fp);
904 fclose(test_type_fp);
905 }
906
cleanup_and_exit(int ret)907 static void __attribute__((noreturn)) cleanup_and_exit(int ret)
908 {
909 cleanup_debugfs();
910 close(drm_fd);
911 igt_info("Compliance testing application exiting\n");
912 exit(ret);
913 }
914
cleanup_test(void)915 static void cleanup_test(void)
916 {
917 video_pattern_flag = false;
918 hdisplay = 0;
919 vdisplay = 0;
920 bitdepth = 0;
921 }
922
read_test_request(void)923 static void read_test_request(void)
924 {
925 unsigned long test_type;
926
927 test_type = get_test_type();
928 process_test_request(test_type);
929 cleanup_test();
930 clear_test_active();
931 }
932
test_handler(GIOChannel * source,GIOCondition condition,gpointer data)933 static gboolean test_handler(GIOChannel *source, GIOCondition condition,
934 gpointer data)
935 {
936 unsigned long test_active;
937 int ret;
938
939 rewind(test_active_fp);
940
941 ret = fscanf(test_active_fp, "%lx", &test_active);
942 if (ret < 1)
943 return FALSE;
944
945 if (test_active)
946 read_test_request();
947 return TRUE;
948 }
949
input_event(GIOChannel * source,GIOCondition condition,gpointer data)950 static gboolean input_event(GIOChannel *source, GIOCondition condition,
951 gpointer data)
952 {
953 gchar buf[2];
954 gsize count;
955
956 count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
957 if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
958 cleanup_and_exit(0);
959 }
960
961 return TRUE;
962 }
963
enter_exec_path(char ** argv)964 static void enter_exec_path(char **argv)
965 {
966 char *exec_path = NULL;
967 char *pos = NULL;
968 short len_path = 0;
969 int ret;
970
971 len_path = strlen(argv[0]);
972 exec_path = (char *) malloc(len_path);
973
974 memcpy(exec_path, argv[0], len_path);
975 pos = strrchr(exec_path, '/');
976 if (pos != NULL)
977 *(pos+1) = '\0';
978
979 ret = chdir(exec_path);
980 igt_assert_eq(ret, 0);
981 free(exec_path);
982 }
983
restore_termio_mode(int sig)984 static void restore_termio_mode(int sig)
985 {
986 tcsetattr(tio_fd, TCSANOW, &saved_tio);
987 close(tio_fd);
988 }
989
set_termio_mode(void)990 static void set_termio_mode(void)
991 {
992 struct termios tio;
993
994 /* don't attempt to set terminal attributes if not in the foreground
995 * process group
996 */
997 if (getpgrp() != tcgetpgrp(STDOUT_FILENO))
998 return;
999
1000 tio_fd = dup(STDIN_FILENO);
1001 tcgetattr(tio_fd, &saved_tio);
1002 igt_install_exit_handler(restore_termio_mode);
1003 tio = saved_tio;
1004 tio.c_lflag &= ~(ICANON | ECHO);
1005 tcsetattr(tio_fd, TCSANOW, &tio);
1006 }
1007
main(int argc,char ** argv)1008 int main(int argc, char **argv)
1009 {
1010 int c;
1011 int ret = 0;
1012 GIOChannel *stdinchannel, *testactive_channel;
1013 GMainLoop *mainloop;
1014 bool opt_dump_info = false;
1015 struct option long_opts[] = {
1016 {"help-description", 0, 0, HELP_DESCRIPTION},
1017 {"help", 0, 0, 'h'},
1018 };
1019
1020 igt_skip_on_simulation();
1021
1022 enter_exec_path(argv);
1023
1024 while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) {
1025 switch (c) {
1026 case 'i':
1027 opt_dump_info = true;
1028 break;
1029 case HELP_DESCRIPTION:
1030 igt_info("DP Compliance Test Suite using DPR-120\n");
1031 igt_info("EDID tests\n");
1032 igt_info("Video Pattern Generation tests\n");
1033 exit(0);
1034 break;
1035 default:
1036 /* fall through */
1037 case 'h':
1038 usage(argv[0], c);
1039 break;
1040 }
1041 }
1042
1043 set_termio_mode();
1044
1045 drm_fd = drm_open_driver(DRIVER_ANY);
1046 gen = intel_gen(intel_get_drm_devid(drm_fd));
1047
1048 kmstest_set_vt_graphics_mode();
1049 setup_debugfs_files();
1050 cleanup_test();
1051
1052 if (opt_dump_info) {
1053 dump_info();
1054 goto out_close;
1055 }
1056
1057 /* Get the DP connector ID and CRTC */
1058 if (update_display(0, false)) {
1059 igt_warn("Failed to set default mode\n");
1060 ret = -1;
1061 goto out_close;
1062 }
1063
1064 mainloop = g_main_loop_new(NULL, FALSE);
1065 if (!mainloop) {
1066 igt_warn("Failed to create GMainLoop\n");
1067 ret = -1;
1068 goto out_close;
1069 }
1070
1071 if (!intel_dp_compliance_setup_hotplug()) {
1072 igt_warn("Failed to initialize hotplug support\n");
1073 goto out_mainloop;
1074 }
1075
1076 testactive_channel = g_io_channel_unix_new(fileno(test_active_fp));
1077 if (!testactive_channel) {
1078 igt_warn("Failed to create test_active GIOChannel\n");
1079 goto out_close;
1080 }
1081
1082 ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR,
1083 test_handler, NULL);
1084 if (ret < 0) {
1085 igt_warn("Failed to add watch on udev GIOChannel\n");
1086 goto out_close;
1087 }
1088
1089 stdinchannel = g_io_channel_unix_new(0);
1090 if (!stdinchannel) {
1091 igt_warn("Failed to create stdin GIOChannel\n");
1092 goto out_hotplug;
1093 }
1094
1095 ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
1096 NULL);
1097 if (ret < 0) {
1098 igt_warn("Failed to add watch on stdin GIOChannel\n");
1099 goto out_stdio;
1100 }
1101
1102 ret = 0;
1103
1104 igt_info("*************DP Compliance Testing using DPR-120*************\n");
1105 igt_info("Waiting for test request......\n");
1106
1107 g_main_loop_run(mainloop);
1108
1109 out_stdio:
1110 g_io_channel_shutdown(stdinchannel, TRUE, NULL);
1111 out_hotplug:
1112 intel_dp_compliance_cleanup_hotplug();
1113 out_mainloop:
1114 g_main_loop_unref(mainloop);
1115 out_close:
1116 cleanup_debugfs();
1117 close(drm_fd);
1118
1119 igt_assert_eq(ret, 0);
1120
1121 igt_info("Compliance testing application exiting\n");
1122 igt_exit();
1123 }
1124