• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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