Message ID | C56C55B681623645A065C9EE352337D6110D5329@ORSMSX109.amr.corp.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi The copyright statements still need the year corrected. intel_dp_compliance needs to be added to tools/.gitignore Some new comments also: - Why do some of the prints have \r\n? - Building intel_dp_compliance should actually be made conditional upon HAVE_UDEV -- Petri Latvala On Fri, Dec 23, 2016 at 09:47:48AM +0200, Pandiyan, Dhinakaran wrote: > I have addressed review comments that Petri, Jim had for this patch along with making some small changes for error handling. The functionality is mostly unchanged from Manasi's version. > > -DK > ________________________________________ > From: Pandiyan, Dhinakaran > Sent: Thursday, December 22, 2016 11:41 PM > To: intel-gfx@lists.freedesktop.org > Cc: jim.bride@linux.intel.com; Navare, Manasi D; Latvala, Petri; Vlad, Marius C; Daniel Vetter; Pandiyan, Dhinakaran > Subject: [PATCH i-g-t v3] tools: Add intel_dp_compliance for DisplayPort 1.2 compliance automation > > From: "Navare, Manasi D" <manasi.d.navare@intel.com> > > This is the userspace component of the Displayport Compliance > testing software required for compliance testing of the I915 > Display Port driver. This must be running in order to successfully > complete Display Port compliance testing. This app and the kernel > code that accompanies it has been written to satify the requirements > of the Displayport Link CTS 1.2 rev1.1 specification from VESA. > Note that this application does not support eDP compliance testing. > This utility has an automation support for the Link training tests > (4.3.1.1. - 4.3.2.3), EDID tests (4.2.2.3 > - 4.2.2.6) and Video Pattern generation tests (4.3.3.1) from CTS > specification 1.2 Rev 1.1. > > This tool has the support for responding to the hotplug uevents > sent by compliance testting unit after each test. > > The Linux DUT running this utility must be in text (console) mode > and cannot have any other display manager running. Since this uses > sysfs nodes for kernel interaction, this utility should be run as > Root. Once this user application is up and running, waiting for > test requests, the test appliance software on the windows host > can now be used to execute the compliance tests. > > This app is based on some prior work done in April 2015 (by > Todd Previte <tprevite@gmail.com>) > > v2: > * Add mode unset on hotplug uevent on disconnect (Manasi Navare) > > v3: > Made capitalization consistent > Reduced line lengths > Added return value checks > Changed how GLib is linked > Fixed build warnings > > Cc: Petri Latvala <petri.latvala@intel.com> > Cc: Marius Vlad <marius.c.vlad@intel.com> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> > --- > tools/Makefile.am | 1 + > tools/Makefile.sources | 7 + > tools/intel_dp_compliance.c | 1104 +++++++++++++++++++++++++++++++++++ > tools/intel_dp_compliance.h | 35 ++ > tools/intel_dp_compliance_hotplug.c | 123 ++++ > 5 files changed, 1270 insertions(+) > create mode 100644 tools/intel_dp_compliance.c > create mode 100644 tools/intel_dp_compliance.h > create mode 100644 tools/intel_dp_compliance_hotplug.c > > diff --git a/tools/Makefile.am b/tools/Makefile.am > index 18f86f6..bd8f512 100644 > --- a/tools/Makefile.am > +++ b/tools/Makefile.am > @@ -16,6 +16,7 @@ AM_CFLAGS = $(DEBUG_CFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) \ > LDADD = $(top_builddir)/lib/libintel_tools.la > AM_LDFLAGS = -Wl,--as-needed > > +intel_dp_compliance_LDADD = $(top_builddir)/lib/libintel_tools.la $(GLIB_LIBS) > > # aubdumper > > diff --git a/tools/Makefile.sources b/tools/Makefile.sources > index e2451ea..e8ce891 100644 > --- a/tools/Makefile.sources > +++ b/tools/Makefile.sources > @@ -13,6 +13,7 @@ tools_prog_lists = \ > intel_bios_reader \ > intel_display_crc \ > intel_display_poller \ > + intel_dp_compliance \ > intel_forcewaked \ > intel_gpu_frequency \ > intel_firmware_decode \ > @@ -56,3 +57,9 @@ intel_l3_parity_SOURCES = \ > intel_l3_parity.h \ > intel_l3_udev_listener.c > > +intel_dp_compliance_SOURCES = \ > + intel_dp_compliance.c \ > + intel_dp_compliance.h \ > + intel_dp_compliance_hotplug.c \ > + $(NULL) > + > diff --git a/tools/intel_dp_compliance.c b/tools/intel_dp_compliance.c > new file mode 100644 > index 0000000..df1ca10 > --- /dev/null > +++ b/tools/intel_dp_compliance.c > @@ -0,0 +1,1104 @@ > +/* > + * Copyright © 2014 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + * > + * Displayport Compliance Testing Application > + * > + * This is the userspace component of the Displayport Compliance testing > + * software required for compliance testing of the I915 Display Port driver. > + * This must be running in order to successfully complete Display Port > + * compliance testing. This app and the kernel code that accompanies it has been > + * written to satify the requirements of the Displayport Link CTS 1.2 rev1.1 > + * specification from VESA. Note that this application does not support eDP > + * compliance testing. > + * > + * Compliance Testing requires several components: > + * - A kernel build that contains the patch set for DP compliance support > + * - A Displayport Compliance Testing appliance such as Unigraf-DPR120 > + * - This user application > + * - A windows host machine to run the DPR test software > + * - Root access on the DUT due to the use of sysfs utility > + * > + * Test Setup: > + * It is strongly recommended that the windows host, test appliance and DUT > + * be freshly restarted before any testing begins to ensure that any previous > + * configurations and settings will not interfere with test process. Refer to > + * the test appliance documentation for setup, software installation and > + * operation specific to that device. > + * > + * The Linux DUT must be in text (console) mode and cannot have any other > + * display manager running. You must be logged in as root to run this user app. > + * Once the user application is up and running, waiting for test requests, the > + * software on the windows host can now be used to execute the compliance tests. > + * > + * This userspace application supports following tests from the DP CTS Spec > + * Rev 1.1: > + * - Link Training Tests: Supports tests 4.3.1.1 to 4.3.2.3 > + * - EDID Tests: Supports EDID read (4.2.2.3),EDID Read failure and corruption > + * detection tests (4.2.2.4, 4.2.2.5, 4.2.2.6) > + * - Video Pattern generation tests: This supports only the 24 and 18bpp color > + * ramp test pattern (4.3.3.1). > + * > + * Connections (required): > + * - Test Appliance connected to the external Displayport connector on the DUT > + * - Test Appliance Monitor Out connected to Displayport connector on the > + * monitor > + * - Test appliance connected to the Windows Host via USB > + * > + * Debugfs Files: > + * The file root for all the debugfs file: > + * /sys/kernel/debug/dri/0/ > + * > + * The specific files are as follows: > + * > + * i915_dp_test_active > + * A simple flag that indicates whether or not compliance testing is currently > + * active in the kernel. This flag is polled by userspace and once set, invokes > + * the test handler in the user app. This flag is set by the test handler in the > + * kernel after reading the registers requested by the test appliance. > + * > + * i915_dp_test_data > + * Test data is used by the kernel to pass parameters to the user app. Eg: In > + * case of EDID tests, the data that is delivered to the userspace is the video > + * mode to be set for the test. > + * In case of video pattern test, the data that is delivered to the userspace is > + * the width and height of the test pattern and the bits per color value. > + * > + * i915_dp_test_type > + * The test type variable instructs the user app as to what the requested test > + * was from the sink device. These values defined at the top of the application's > + * main implementation file must be kept in sync with the values defined in the > + * kernel's drm_dp_helper.h file. > + * This app is based on some prior work submitted in April 2015 by Todd Previte > + * (<tprevite@gmail.com>) > + * > + * > + * This tool can be run as: > + * ./intel_dp_compliance It will wait till you start compliance suite from > + * DPR 120. > + * ./intel_dp_compliance -h This will open the help > + * ./intel_dp_compliance -i This will provide information about current > + * connectors/CRTCs. This can be used for debugging purpose. > + * > + * Authors: > + * Manasi Navare <manasi.d.navare@intel.com> > + * > + * Elements of the modeset code adapted from David Herrmann's > + * DRM modeset example > + * > + */ > +#include "igt.h" > +#include <errno.h> > +#include <getopt.h> > +#include <math.h> > +#include <stdint.h> > +#include <stdbool.h> > +#include <strings.h> > +#include <unistd.h> > +#include <termios.h> > +#include <sys/poll.h> > +#include <sys/time.h> > +#include <sys/ioctl.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <sys/select.h> > +#include <assert.h> > +#include <signal.h> > +#include <fcntl.h> > +#include <time.h> > + > +#include "intel_dp_compliance.h" > + > +#include <stdlib.h> > +#include <signal.h> > + > +/* User Input definitions */ > +#define HELP_DESCRIPTION 1 > + > +/* Debugfs file definitions */ > +#define INTEL_DP_TEST_TYPE_FILE "i915_dp_test_type" > +#define INTEL_DP_TEST_ACTIVE_FILE "i915_dp_test_active" > +#define INTEL_DP_TEST_DATA_FILE "i915_dp_test_data" > + > +/* DRM definitions - must be kept in sync with the DRM header */ > +#define DP_TEST_LINK_TRAINING (1 << 0) > +#define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) > +#define DP_TEST_LINK_EDID_READ (1 << 2) > +#define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ > + > +#define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING | \ > + DP_TEST_LINK_VIDEO_PATTERN | \ > + DP_TEST_LINK_EDID_READ | \ > + DP_TEST_LINK_PHY_TEST_PATTERN) > + > +/* NOTE: These must be kept in sync with the definitions in intel_dp.c */ > +#define INTEL_DP_EDID_SHIFT_MASK 0 > +#define INTEL_DP_EDID_OK (0 << INTEL_DP_EDID_SHIFT_MASK) > +#define INTEL_DP_EDID_CORRUPT (1 << INTEL_DP_EDID_SHIFT_MASK) > +#define INTEL_DP_RESOLUTION_SHIFT_MASK 0 > +#define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK) > +#define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK) > +#define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) > +#define DP_COMPLIANCE_VIDEO_MODE_MASK (INTEL_DP_RESOLUTION_PREFERRED |\ > + INTEL_DP_RESOLUTION_STANDARD |\ > + INTEL_DP_RESOLUTION_FAILSAFE) > + > +/* Global file pointers for the sysfs files */ > +FILE *test_active_fp, *test_data_fp, *test_type_fp; > + > +bool video_pattern_flag; > + > +/* Video pattern test globals */ > +uint16_t hdisplay; > +uint16_t vdisplay; > +uint8_t bitdepth; > + > +static int tio_fd; > +struct termios saved_tio; > + > +drmModeRes *resources; > +int drm_fd, modes; > +uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE; > +uint32_t depth = 24, stride, bpp; > +int specified_mode_num = -1, specified_disp_id = -1; > +int width, height; > +uint32_t test_crtc; > +uint32_t test_connector_id; > +enum { > + INTEL_MODE_INVALID = -1, > + INTEL_MODE_NONE = 0, > + INTEL_MODE_PREFERRED, > + INTEL_MODE_STANDARD, > + INTEL_MODE_FAILSAFE, > + INTEL_MODE_VIDEO_PATTERN_TEST > +} intel_display_mode; > + > +struct test_video_pattern { > + uint16_t hdisplay; > + uint16_t vdisplay; > + uint8_t bitdepth; > + uint32_t fb; > + uint32_t size; > + struct igt_fb fb_pattern; > + drmModeModeInfo mode; > + uint32_t *pixmap; > +}; > + > +struct connector { > + uint32_t id; > + int mode_valid; > + drmModeModeInfo mode, mode_standard, mode_preferred, mode_failsafe; > + drmModeConnector *connector; > + int crtc; > + /* Standard and preferred frame buffer*/ > + uint32_t fb, fb_width, fb_height, fb_size; > + uint8_t *pixmap; > + struct igt_fb fb_video_pattern; > + /* Failsafe framebuffer - note this is a 16-bit buffer */ > + uint32_t failsafe_fb, failsafe_width, failsafe_height; > + uint32_t failsafe_size; > + uint8_t *failsafe_pixmap; > + struct igt_fb fb_failsafe_pattern; > + struct test_video_pattern test_pattern; > +}; > + > +static void clear_test_active(void) > +{ > + rewind(test_active_fp); > + fprintf(test_active_fp, "%d", 0); > + fflush(test_active_fp); > +} > + > +static void setup_debugfs_files(void) > +{ > + test_type_fp = igt_debugfs_fopen(INTEL_DP_TEST_TYPE_FILE, "r"); > + igt_require(test_type_fp); > + > + test_data_fp = igt_debugfs_fopen(INTEL_DP_TEST_DATA_FILE, "r"); > + igt_require(test_data_fp); > + > + test_active_fp = igt_debugfs_fopen(INTEL_DP_TEST_ACTIVE_FILE, "w+"); > + igt_require(test_active_fp); > + > + /* Reset the active flag for safety */ > + clear_test_active(); > +} > + > +static unsigned long get_test_type(void) > +{ > + unsigned long test_type; > + int ret; > + > + if (!test_type_fp) > + fprintf(stderr, "Invalid test_type file\r\n"); > + rewind(test_type_fp); > + ret = fscanf(test_type_fp, "%02lx", &test_type); > + if (ret < 1 || test_type <= 0) { > + igt_warn("test_type read failed - %02lx\r\n", test_type); > + return 0; > + } > + > + return test_type; > +} > + > +static unsigned long get_test_edid_data(void) > +{ > + unsigned long test_data; > + int ret; > + > + if (!test_data_fp) > + fprintf(stderr, "Invalid test_data file\r\n"); > + > + rewind(test_data_fp); > + ret = fscanf(test_data_fp, "%lx", &test_data); > + if (ret < 1 || test_data <= 0) { > + igt_warn("test_data read failed - %lx\r\n", test_data); > + return 0; > + } > + > + return test_data; > +} > + > +static void get_test_videopattern_data(void) > +{ > + int count = 0; > + uint16_t video_pattern_value[3]; > + char video_pattern_attribute[15]; > + int ret; > + > + if (!test_data_fp) > + fprintf(stderr, "Invalid test_data file\r\n"); > + > + rewind(test_data_fp); > + while (!feof(test_data_fp) && count < 3) { > + ret = fscanf(test_data_fp, "%s %u\n", video_pattern_attribute, > + (unsigned int *)&video_pattern_value[count++]); > + if (ret < 2) { > + igt_warn("test_data read failed\n"); > + return; > + } > + } > + > + hdisplay = video_pattern_value[0]; > + vdisplay = video_pattern_value[1]; > + bitdepth = video_pattern_value[2]; > + igt_info("Hdisplay = %d\r\n", hdisplay); > + igt_info("Vdisplay = %d\r\n", vdisplay); > + igt_info("BitDepth = %u\r\n", bitdepth); > + > +} > + > +static int process_test_request(int test_type) > +{ > + int mode; > + unsigned long test_data_edid; > + bool valid = false; > + switch (test_type) { > + case DP_TEST_LINK_VIDEO_PATTERN: > + video_pattern_flag = true; > + get_test_videopattern_data(); > + mode = INTEL_MODE_VIDEO_PATTERN_TEST; > + valid = true; > + break; > + case DP_TEST_LINK_EDID_READ: > + test_data_edid = get_test_edid_data(); > + mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >> > + INTEL_DP_RESOLUTION_SHIFT_MASK; > + valid = true; > + break; > + default: > + /* Unknown test type */ > + fprintf(stderr, "Invalid test request, ignored.\r\n"); > + break; > + } > + > + if (valid) > + return update_display(mode, true); > + > + return -1; > +} > + > +static void dump_connectors_fd(int drmfd) > +{ > + int i, j; > + > + drmModeRes *mode_resources = drmModeGetResources(drmfd); > + > + if (!mode_resources) { > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > + return; > + } > + > + igt_info("Connectors:\n"); > + igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); > + for (i = 0; i < mode_resources->count_connectors; i++) { > + drmModeConnector *connector; > + > + connector = drmModeGetConnectorCurrent(drmfd, > + mode_resources->connectors[i]); > + if (!connector) { > + igt_warn("Could not get connector %i: %s\n", > + mode_resources->connectors[i], strerror(errno)); > + continue; > + } > + > + igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", > + connector->connector_id, > + connector->encoder_id, > + kmstest_connector_status_str(connector->connection), > + kmstest_connector_type_str(connector->connector_type), > + connector->mmWidth, > + connector->mmHeight, > + connector->count_modes); > + > + if (!connector->count_modes) > + continue; > + > + igt_info(" Modes:\n"); > + igt_info(" name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n"); > + for (j = 0; j < connector->count_modes; j++) { > + igt_info("[%d]", j); > + kmstest_dump_mode(&connector->modes[j]); > + } > + > + drmModeFreeConnector(connector); > + } > + igt_info("\n"); > + > + drmModeFreeResources(mode_resources); > +} > + > +static void dump_crtcs_fd(int drmfd) > +{ > + int i; > + drmModeRes *mode_resources; > + > + mode_resources = drmModeGetResources(drmfd); > + if (!mode_resources) { > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > + return; > + } > + > + igt_info("CRTCs:\n"); > + igt_info("id\tfb\tpos\tsize\n"); > + for (i = 0; i < mode_resources->count_crtcs; i++) { > + drmModeCrtc *crtc; > + > + crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]); > + if (!crtc) { > + igt_warn("Could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno)); > + continue; > + } > + igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n", > + crtc->crtc_id, > + crtc->buffer_id, > + crtc->x, > + crtc->y, > + crtc->width, > + crtc->height); > + > + kmstest_dump_mode(&crtc->mode); > + > + drmModeFreeCrtc(crtc); > + } > + igt_info("\n"); > + > + drmModeFreeResources(mode_resources); > +} > + > +static void dump_info(void) > +{ > + dump_connectors_fd(drm_fd); > + dump_crtcs_fd(drm_fd); > +} > + > +static int setup_framebuffers(struct connector *dp_conn) > +{ > + > + dp_conn->fb = igt_create_fb(drm_fd, > + dp_conn->fb_width, dp_conn->fb_height, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD_NONE, > + &dp_conn->fb_video_pattern); > + igt_assert(dp_conn->fb); > + > + /* Map the mapping of GEM object into the virtual address space */ > + dp_conn->pixmap = gem_mmap__gtt(drm_fd, > + dp_conn->fb_video_pattern.gem_handle, > + dp_conn->fb_video_pattern.size, > + PROT_READ | PROT_WRITE); > + if (dp_conn->pixmap == NULL) > + return -1; > + > + gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle, > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > + dp_conn->fb_size = dp_conn->fb_video_pattern.size; > + > + /* After filling the device memory with 0s it needs to be unmapped */ > + memset(dp_conn->pixmap, 0, dp_conn->fb_size); > + munmap(dp_conn->pixmap, dp_conn->fb_size); > + > + return 0; > +} > + > +static int setup_failsafe_framebuffer(struct connector *dp_conn) > +{ > + > + dp_conn->failsafe_fb = igt_create_fb(drm_fd, > + dp_conn->failsafe_width, > + dp_conn->failsafe_height, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD_NONE, > + &dp_conn->fb_failsafe_pattern); > + igt_assert(dp_conn->failsafe_fb); > + > + /* Map the mapping of GEM object into the virtual address space */ > + dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd, > + dp_conn->fb_failsafe_pattern.gem_handle, > + dp_conn->fb_failsafe_pattern.size, > + PROT_READ | PROT_WRITE); > + if (dp_conn->failsafe_pixmap == NULL) > + return -1; > + > + gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle, > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > + dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size; > + > + /* After filling the device framebuffer the mapped memory needs to be freed */ > + memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size); > + munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size); > + > + return 0; > + > +} > + > +static int setup_video_pattern_framebuffer(struct connector *dp_conn) > +{ > + uint32_t video_width, video_height; > + > + video_width = dp_conn->test_pattern.hdisplay; > + video_height = dp_conn->test_pattern.vdisplay; > + dp_conn->test_pattern.fb = igt_create_fb(drm_fd, > + video_width, video_height, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD_NONE, > + &dp_conn->test_pattern.fb_pattern); > + igt_assert(dp_conn->test_pattern.fb); > + > + /* Map the mapping of GEM object into the virtual address space */ > + dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd, > + dp_conn->test_pattern.fb_pattern.gem_handle, > + dp_conn->test_pattern.fb_pattern.size, > + PROT_READ | PROT_WRITE); > + if (dp_conn->test_pattern.pixmap == NULL) > + return -1; > + > + gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle, > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > + > + dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size; > + > + memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size); > + return 0; > + > +} > + > +static int fill_framebuffer(struct connector *dp_conn) > +{ > + uint32_t tile_height, tile_width, video_width, video_height; > + uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr; > + int x, y; > + int32_t pixel_val; > + > + video_width = dp_conn->test_pattern.hdisplay; > + video_height = dp_conn->test_pattern.vdisplay; > + > + tile_height = 64; > + tile_width = 1 << (dp_conn->test_pattern.bitdepth); > + > + red_ptr = dp_conn->test_pattern.pixmap; > + green_ptr = red_ptr + (video_width * tile_height); > + blue_ptr = green_ptr + (video_width * tile_height); > + white_ptr = blue_ptr + (video_width * tile_height); > + x = 0; > + > + /* Fill the frame buffer with video pattern from CTS 3.1.5 */ > + while (x < video_width) { > + for (pixel_val = 0; pixel_val < 256; > + pixel_val = pixel_val + (256 / tile_width)) { > + red_ptr[x] = pixel_val << 16; > + green_ptr[x] = pixel_val << 8; > + blue_ptr[x] = pixel_val << 0; > + white_ptr[x] = red_ptr[x] | green_ptr[x] | blue_ptr[x]; > + if (++x >= video_width) > + break; > + } > + } > + for (y = 0; y < video_height; y++) { > + if (y == 0 || y == 64 || y == 128 || y == 192) > + continue; > + switch ((y / tile_height) % 4) { > + case 0: > + src_ptr = red_ptr; > + break; > + case 1: > + src_ptr = green_ptr; > + break; > + case 2: > + src_ptr = blue_ptr; > + break; > + case 3: > + src_ptr = white_ptr; > + break; > + } > + dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width); > + memcpy(dst_ptr, src_ptr, (video_width * 4)); > + } > + munmap(dp_conn->test_pattern.pixmap, > + dp_conn->test_pattern.size); > + return 0; > +} > + > +static int set_test_mode(struct connector *dp_conn) > +{ > + int ret = 0; > + int i; > + bool found_std = false, found_fs = false; > + drmModeConnector *c = dp_conn->connector; > + > + /* Ignore any disconnected devices */ > + if (c->connection != DRM_MODE_CONNECTED) { > + igt_warn("Connector %u disconnected\r\n", c->connector_id); > + return -ENOENT; > + } > + igt_info("Connector setup:\r\n"); > + /* Setup preferred mode - should be mode[0] in the list */ > + dp_conn->mode_preferred = c->modes[0]; > + dp_conn->fb_width = c->modes[0].hdisplay; > + dp_conn->fb_height = c->modes[0].vdisplay; > + > + dp_conn->test_pattern.mode = c->modes[0]; > + dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay; > + dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay; > + > + igt_info("Preferred mode (mode 0) for connector %u is %ux%u\r\n", > + dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay); > + fflush(stdin); > + > + for (i = 1; i < c->count_modes; i++) { > + /* Standard mode is 800x600@60 */ > + if (c->modes[i].hdisplay == 800 && > + c->modes[i].vdisplay == 600 && > + c->modes[i].vrefresh == 60 && > + found_std == false) { > + dp_conn->mode_standard = c->modes[i]; > + igt_info("Standard mode (%d) for connector %u is %ux%u\r\n", > + i, > + c->connector_id, > + c->modes[i].hdisplay, > + c->modes[i].vdisplay); > + found_std = true; > + } > + /* Failsafe mode is 640x480@60 */ > + if (c->modes[i].hdisplay == 640 && > + c->modes[i].vdisplay == 480 && > + c->modes[i].vrefresh == 60 && > + found_fs == false) { > + dp_conn->mode_failsafe = c->modes[i]; > + dp_conn->failsafe_width = c->modes[i].hdisplay; > + dp_conn->failsafe_height = c->modes[i].vdisplay; > + igt_info("Failsafe mode (%d) for connector %u is %ux%u\r\n", > + i, > + c->connector_id, > + c->modes[i].hdisplay, > + c->modes[i].vdisplay); > + found_fs = true; > + } > + } > + > + ret = setup_framebuffers(dp_conn); > + if (ret) { > + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", > + c->connector_id, ret); > + return ret; > + } > + > + if (found_fs) { > + ret = setup_failsafe_framebuffer(dp_conn); > + if (ret) { > + igt_warn("Creating failsafe framebuffer for connector %u failed (%d)\r\n", > + c->connector_id, ret); > + return ret; > + } > + } > + > + if (video_pattern_flag) { > + dp_conn->test_pattern.hdisplay = hdisplay; > + dp_conn->test_pattern.vdisplay = vdisplay; > + dp_conn->test_pattern.bitdepth = bitdepth; > + > + ret = setup_video_pattern_framebuffer(dp_conn); > + if (ret) { > + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", > + c->connector_id, ret); > + return ret; > + } > + > + ret = fill_framebuffer(dp_conn); > + if (ret) { > + igt_warn("Filling framebuffer for connector %u failed (%d)\r\n", > + c->connector_id, ret); > + return ret; > + } > + } > + > + return ret; > +} > + > +static int set_video(int mode, struct connector *test_connector) > +{ > + drmModeModeInfo *requested_mode; > + uint32_t required_fb_id; > + struct igt_fb required_fb; > + int ret = 0; > + > + switch (mode) { > + case INTEL_MODE_NONE: > + igt_info("NONE\r\n"); > + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, > + -1, 0, 0, NULL, 0, NULL); > + goto out; > + case INTEL_MODE_PREFERRED: > + igt_info("PREFERRED\r\n"); > + requested_mode = &test_connector->mode_preferred; > + required_fb_id = test_connector->fb; > + required_fb = test_connector->fb_video_pattern; > + break; > + case INTEL_MODE_STANDARD: > + igt_info("STANDARD\r\n"); > + requested_mode = &test_connector->mode_standard; > + required_fb_id = test_connector->fb; > + required_fb = test_connector->fb_video_pattern; > + break; > + case INTEL_MODE_FAILSAFE: > + igt_info("FAILSAFE\r\n"); > + requested_mode = &test_connector->mode_failsafe; > + required_fb_id = test_connector->failsafe_fb; > + required_fb = test_connector->fb_failsafe_pattern; > + break; > + case INTEL_MODE_VIDEO_PATTERN_TEST: > + igt_info("VIDEO PATTERN TEST\r\n"); > + requested_mode = &test_connector->test_pattern.mode; > + required_fb_id = test_connector->test_pattern.fb; > + required_fb = test_connector->test_pattern.fb_pattern; > + break; > + case INTEL_MODE_INVALID: > + default: > + igt_warn("INVALID! (%08x) Mode set aborted!\r\n", mode); > + return -1; > + } > + > + igt_info("CRTC(%u):", test_connector->crtc); > + kmstest_dump_mode(requested_mode); > + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0, > + &test_connector->id, 1, requested_mode); > + if (ret) { > + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", > + requested_mode->hdisplay, requested_mode->vdisplay, > + requested_mode->vrefresh, strerror(errno)); > + igt_remove_fb(drm_fd, &required_fb); > + > + } > + /* Keep the pattern on output lines for 1 sec for DPR-120 to detect it */ > + sleep(1); > + > +out: > + if (ret) { > + igt_warn("Failed to set CRTC for connector %u\r\n", > + test_connector->id); > + } > + > + return ret; > +} > + > +static int > +set_default_mode(struct connector *c, bool set_mode) > +{ > + unsigned int fb_id = 0; > + struct igt_fb fb_info; > + int ret = 0; > + > + if (!set_mode) { > + ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0, > + NULL, 0, NULL); > + if (ret) > + igt_warn("Failed to unset mode"); > + return ret; > + } > + > + c->mode = c->connector->modes[0]; > + > + width = c->mode.hdisplay; > + height = c->mode.vdisplay; > + > + fb_id = igt_create_pattern_fb(drm_fd, width, height, > + DRM_FORMAT_XRGB8888, > + tiling, &fb_info); > + > + igt_info("CRTC(%u):[%d]", c->crtc, 0); > + kmstest_dump_mode(&c->mode); > + drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL); > + ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, > + &c->id, 1, &c->mode); > + if (ret) { > + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", > + width, height, c->mode.vrefresh, strerror(errno)); > + igt_remove_fb(drm_fd, &fb_info); > + > + } > + > + return ret; > +} > + > +static uint32_t find_crtc_for_connector(drmModeConnector *c) > +{ > + drmModeEncoder *e; > + uint32_t possible_crtcs; > + int i, j; > + > + for (i = 0; i < c->count_encoders; i++) { > + e = drmModeGetEncoder(drm_fd, c->encoders[i]); > + possible_crtcs = e->possible_crtcs; > + drmModeFreeEncoder(e); > + > + for (j = 0; possible_crtcs >> j; j++) > + if (possible_crtcs & (1 << j)) > + return resources->crtcs[j]; > + } > + return 0; > +} > + > +/* > + * Re-probe connectors and do a modeset based on test request or > + * in case of a hotplug uevent. > + * > + * @mode: Video mode requested by the test > + * @is_compliance_test: 1: If it is a compliance test > + * 0: If it is a hotplug event > + * > + * Returns: > + * 0: On Success > + * -1: On failure > + */ > +int update_display(int mode, bool is_compliance_test) > +{ > + struct connector *connectors, *conn; > + int cnt, ret = 0; > + bool set_mode; > + > + resources = drmModeGetResources(drm_fd); > + if (!resources) { > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > + return -1; > + } > + > + connectors = calloc(resources->count_connectors, > + sizeof(struct connector)); > + if (!connectors) > + return -1; > + > + /* Find any connected displays */ > + for (cnt = 0; cnt < resources->count_connectors; cnt++) { > + drmModeConnector *c; > + > + conn = &connectors[cnt]; > + conn->id = resources->connectors[cnt]; > + c = drmModeGetConnector(drm_fd, conn->id); > + if (c->connector_type == DRM_MODE_CONNECTOR_DisplayPort && > + c->connection == DRM_MODE_CONNECTED) { > + test_connector_id = c->connector_id; > + conn->connector = c; > + conn->crtc = find_crtc_for_connector(c); > + test_crtc = conn->crtc; > + set_mode = true; > + break; > + } else if (c->connector_id == test_connector_id && > + c->connection == DRM_MODE_DISCONNECTED) { > + conn->connector = c; > + conn->crtc = test_crtc; > + set_mode = false; > + break; > + } > + } > + > + if (cnt == resources->count_connectors) { > + ret = -1; > + goto err; > + } > + > + if (is_compliance_test) { > + set_test_mode(conn); > + ret = set_video(INTEL_MODE_NONE, conn); > + ret = set_video(mode, conn); > + > + } else > + ret = set_default_mode(conn, set_mode); > + > + err: > + drmModeFreeConnector(conn->connector); > + /* Error condition if no connected displays */ > + free(connectors); > + drmModeFreeResources(resources); > + return ret; > +} > + > +static const char optstr[] = "hi"; > + > +static void __attribute__((noreturn)) usage(char *name, char opt) > +{ > + igt_info("usage: %s [-hi]\n", name); > + igt_info("\t-i\tdump info\n"); > + igt_info("\tDefault is to respond to DPR-120 tests\n"); > + exit((opt != 'h') ? -1 : 0); > +} > + > +static void cleanup_debugfs(void) > +{ > + fclose(test_active_fp); > + fclose(test_data_fp); > + fclose(test_type_fp); > +} > + > +static void __attribute__((noreturn)) cleanup_and_exit(int ret) > +{ > + cleanup_debugfs(); > + close(drm_fd); > + igt_info("Compliance testing application exiting\n"); > + exit(ret); > +} > + > +static void cleanup_test(void) > +{ > + video_pattern_flag = false; > + hdisplay = 0; > + vdisplay = 0; > + bitdepth = 0; > +} > + > +static void read_test_request(void) > +{ > + unsigned long test_type; > + > + test_type = get_test_type(); > + process_test_request(test_type); > + cleanup_test(); > + clear_test_active(); > +} > + > +static gboolean test_handler(GIOChannel *source, GIOCondition condition, > + gpointer data) > +{ > + unsigned long test_active; > + int ret; > + > + rewind(test_active_fp); > + > + ret = fscanf(test_active_fp, "%lx", &test_active); > + if (ret < 1) > + return FALSE; > + > + if (test_active) > + read_test_request(); > + return TRUE; > +} > + > +static gboolean input_event(GIOChannel *source, GIOCondition condition, > + gpointer data) > +{ > + gchar buf[2]; > + gsize count; > + > + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf)); > + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) { > + cleanup_and_exit(0); > + } > + > + return TRUE; > +} > + > +static void enter_exec_path(char **argv) > +{ > + char *exec_path = NULL; > + char *pos = NULL; > + short len_path = 0; > + int ret; > + > + len_path = strlen(argv[0]); > + exec_path = (char *) malloc(len_path); > + > + memcpy(exec_path, argv[0], len_path); > + pos = strrchr(exec_path, '/'); > + if (pos != NULL) > + *(pos+1) = '\0'; > + > + ret = chdir(exec_path); > + igt_assert_eq(ret, 0); > + free(exec_path); > +} > + > +static void restore_termio_mode(int sig) > +{ > + tcsetattr(tio_fd, TCSANOW, &saved_tio); > + close(tio_fd); > +} > + > +static void set_termio_mode(void) > +{ > + struct termios tio; > + > + /* don't attempt to set terminal attributes if not in the foreground > + * process group > + */ > + if (getpgrp() != tcgetpgrp(STDOUT_FILENO)) > + return; > + > + tio_fd = dup(STDIN_FILENO); > + tcgetattr(tio_fd, &saved_tio); > + igt_install_exit_handler(restore_termio_mode); > + tio = saved_tio; > + tio.c_lflag &= ~(ICANON | ECHO); > + tcsetattr(tio_fd, TCSANOW, &tio); > +} > + > +int main(int argc, char **argv) > +{ > + int c; > + int ret = 0; > + GIOChannel *stdinchannel, *testactive_channel; > + GMainLoop *mainloop; > + bool opt_dump_info = false; > + struct option long_opts[] = { > + {"help-description", 0, 0, HELP_DESCRIPTION}, > + {"help", 0, 0, 'h'}, > + }; > + > + igt_skip_on_simulation(); > + > + enter_exec_path(argv); > + > + while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) { > + switch (c) { > + case 'i': > + opt_dump_info = true; > + break; > + case HELP_DESCRIPTION: > + igt_info("DP Compliance Test Suite using DPR-120\n"); > + igt_info("EDID tests\n"); > + igt_info("Video Pattern Generation tests\n"); > + exit(0); > + break; > + default: > + /* fall through */ > + case 'h': > + usage(argv[0], c); > + break; > + } > + } > + > + set_termio_mode(); > + > + igt_info("*************DP Compliance Testing using DPR-120*************\n"); > + igt_info("Waiting for test request......\n"); > + drm_fd = drm_open_driver(DRIVER_ANY); > + > + kmstest_set_vt_graphics_mode(); > + setup_debugfs_files(); > + cleanup_test(); > + > + if (opt_dump_info) { > + dump_info(); > + goto out_close; > + } > + > + /* Get the DP connector ID and CRTC */ > + if (update_display(0, false)) { > + igt_warn("Failed to set default mode\n"); > + ret = -1; > + goto out_close; > + } > + > + mainloop = g_main_loop_new(NULL, FALSE); > + if (!mainloop) { > + igt_warn("Failed to create GMainLoop\n"); > + ret = -1; > + goto out_close; > + } > + > + if (!intel_dp_compliance_setup_hotplug()) { > + igt_warn("Failed to initialize hotplug support\n"); > + goto out_mainloop; > + } > + > + testactive_channel = g_io_channel_unix_new(fileno(test_active_fp)); > + if (!testactive_channel) { > + igt_warn("Failed to create test_active GIOChannel\n"); > + goto out_close; > + } > + > + ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR, > + test_handler, NULL); > + if (ret < 0) { > + igt_warn("Failed to add watch on udev GIOChannel\n"); > + goto out_close; > + } > + > + stdinchannel = g_io_channel_unix_new(0); > + if (!stdinchannel) { > + igt_warn("Failed to create stdin GIOChannel\n"); > + goto out_hotplug; > + } > + > + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event, > + NULL); > + if (ret < 0) { > + igt_warn("Failed to add watch on stdin GIOChannel\n"); > + goto out_stdio; > + } > + > + ret = 0; > + > + g_main_loop_run(mainloop); > + > +out_stdio: > + g_io_channel_shutdown(stdinchannel, TRUE, NULL); > +out_hotplug: > + intel_dp_compliance_cleanup_hotplug(); > +out_mainloop: > + g_main_loop_unref(mainloop); > +out_close: > + cleanup_debugfs(); > + close(drm_fd); > + > + igt_assert_eq(ret, 0); > + > + igt_info("Compliance testing application exiting\n"); > + igt_exit(); > +} > diff --git a/tools/intel_dp_compliance.h b/tools/intel_dp_compliance.h > new file mode 100644 > index 0000000..ade1e2f > --- /dev/null > +++ b/tools/intel_dp_compliance.h > @@ -0,0 +1,35 @@ > +/* > + * Copyright 2010 Intel Corporation > + * Manasi Navare <manasi.d.navare@intel.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include <stdio.h> > +#include <string.h> > +#include <stdlib.h> > +#include <glib.h> > + > +extern int drm_fd; > + > +gboolean intel_dp_compliance_setup_hotplug(void); > +void intel_dp_compliance_cleanup_hotplug(void); > + > +/* called by the hotplug code */ > +int update_display(int mode, bool is_compliance_test); > diff --git a/tools/intel_dp_compliance_hotplug.c b/tools/intel_dp_compliance_hotplug.c > new file mode 100644 > index 0000000..7c7ea65 > --- /dev/null > +++ b/tools/intel_dp_compliance_hotplug.c > @@ -0,0 +1,123 @@ > +/* > + * Copyright 2010 Intel Corporation > + * Jesse Barnes <jesse.barnes@intel.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include "igt.h" > +#include <stdio.h> > +#include <string.h> > +#include <stdlib.h> > + > +#include <sys/stat.h> > + > +#include "intel_dp_compliance.h" > +#include <libudev.h> > +static struct udev_monitor *uevent_monitor; > +static struct udev *udev; > +static GIOChannel *udevchannel; > + > +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition, > + gpointer data) > +{ > + struct udev_device *dev; > + dev_t udev_devnum; > + struct stat s; > + const char *hotplug; > + > + dev = udev_monitor_receive_device(uevent_monitor); > + if (!dev) > + goto out; > + > + udev_devnum = udev_device_get_devnum(dev); > + fstat(drm_fd, &s); > + > + hotplug = udev_device_get_property_value(dev, "HOTPLUG"); > + > + if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 && > + hotplug && atoi(hotplug) == 1) > + update_display(0, false); > + > + udev_device_unref(dev); > +out: > + return TRUE; > +} > + > + > +gboolean intel_dp_compliance_setup_hotplug(void) > +{ > + int ret; > + > + udev = udev_new(); > + if (!udev) { > + igt_warn("Failed to create udev object\n"); > + goto out; > + } > + > + uevent_monitor = udev_monitor_new_from_netlink(udev, "udev"); > + if (!uevent_monitor) { > + igt_warn("Failed to create udev event monitor\n"); > + goto out; > + } > + > + ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor, > + "drm", > + "drm_minor"); > + if (ret < 0) { > + igt_warn("Failed to filter for drm events\n"); > + goto out; > + } > + > + ret = udev_monitor_enable_receiving(uevent_monitor); > + if (ret < 0) { > + igt_warn("Failed to enable udev event reception\n"); > + goto out; > + } > + > + udevchannel = > + g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor)); > + if (!udevchannel) { > + igt_warn("Failed to create udev GIOChannel\n"); > + goto out; > + } > + > + ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event, > + udev); > + if (ret < 0) { > + igt_warn("Failed to add watch on udev GIOChannel\n"); > + goto out; > + } > + > + return TRUE; > + > +out: > + intel_dp_compliance_cleanup_hotplug(); > + return FALSE; > +} > + > +void intel_dp_compliance_cleanup_hotplug(void) > +{ > + if (udevchannel) > + g_io_channel_shutdown(udevchannel, TRUE, NULL); > + if (uevent_monitor) > + udev_monitor_unref(uevent_monitor); > + if (udev) > + udev_unref(udev); > +} > -- > 2.7.4 >
On Wed, Jan 11, 2017 at 03:44:12PM +0200, Petri Latvala wrote: > > Hi > > The copyright statements still need the year > corrected. intel_dp_compliance needs to be added to tools/.gitignore > > Some new comments also: > > - Why do some of the prints have \r\n? The \r\n is required in some of the prints so that the output prints are properly aligned. > - Building intel_dp_compliance should actually be made conditional upon HAVE_UDEV > I didnt find any conditional HAVE_UDEV builds in the existing Makefile. How can I build intel-dp_compliance conditionally on HAVE_UDEV? Could you point me to some example in the existing Makefile? Manasi > > > -- > Petri Latvala > > > > On Fri, Dec 23, 2016 at 09:47:48AM +0200, Pandiyan, Dhinakaran wrote: > > I have addressed review comments that Petri, Jim had for this patch along with making some small changes for error handling. The functionality is mostly unchanged from Manasi's version. > > > > -DK > > ________________________________________ > > From: Pandiyan, Dhinakaran > > Sent: Thursday, December 22, 2016 11:41 PM > > To: intel-gfx@lists.freedesktop.org > > Cc: jim.bride@linux.intel.com; Navare, Manasi D; Latvala, Petri; Vlad, Marius C; Daniel Vetter; Pandiyan, Dhinakaran > > Subject: [PATCH i-g-t v3] tools: Add intel_dp_compliance for DisplayPort 1.2 compliance automation > > > > From: "Navare, Manasi D" <manasi.d.navare@intel.com> > > > > This is the userspace component of the Displayport Compliance > > testing software required for compliance testing of the I915 > > Display Port driver. This must be running in order to successfully > > complete Display Port compliance testing. This app and the kernel > > code that accompanies it has been written to satify the requirements > > of the Displayport Link CTS 1.2 rev1.1 specification from VESA. > > Note that this application does not support eDP compliance testing. > > This utility has an automation support for the Link training tests > > (4.3.1.1. - 4.3.2.3), EDID tests (4.2.2.3 > > - 4.2.2.6) and Video Pattern generation tests (4.3.3.1) from CTS > > specification 1.2 Rev 1.1. > > > > This tool has the support for responding to the hotplug uevents > > sent by compliance testting unit after each test. > > > > The Linux DUT running this utility must be in text (console) mode > > and cannot have any other display manager running. Since this uses > > sysfs nodes for kernel interaction, this utility should be run as > > Root. Once this user application is up and running, waiting for > > test requests, the test appliance software on the windows host > > can now be used to execute the compliance tests. > > > > This app is based on some prior work done in April 2015 (by > > Todd Previte <tprevite@gmail.com>) > > > > v2: > > * Add mode unset on hotplug uevent on disconnect (Manasi Navare) > > > > v3: > > Made capitalization consistent > > Reduced line lengths > > Added return value checks > > Changed how GLib is linked > > Fixed build warnings > > > > Cc: Petri Latvala <petri.latvala@intel.com> > > Cc: Marius Vlad <marius.c.vlad@intel.com> > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch> > > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> > > --- > > tools/Makefile.am | 1 + > > tools/Makefile.sources | 7 + > > tools/intel_dp_compliance.c | 1104 +++++++++++++++++++++++++++++++++++ > > tools/intel_dp_compliance.h | 35 ++ > > tools/intel_dp_compliance_hotplug.c | 123 ++++ > > 5 files changed, 1270 insertions(+) > > create mode 100644 tools/intel_dp_compliance.c > > create mode 100644 tools/intel_dp_compliance.h > > create mode 100644 tools/intel_dp_compliance_hotplug.c > > > > diff --git a/tools/Makefile.am b/tools/Makefile.am > > index 18f86f6..bd8f512 100644 > > --- a/tools/Makefile.am > > +++ b/tools/Makefile.am > > @@ -16,6 +16,7 @@ AM_CFLAGS = $(DEBUG_CFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) \ > > LDADD = $(top_builddir)/lib/libintel_tools.la > > AM_LDFLAGS = -Wl,--as-needed > > > > +intel_dp_compliance_LDADD = $(top_builddir)/lib/libintel_tools.la $(GLIB_LIBS) > > > > # aubdumper > > > > diff --git a/tools/Makefile.sources b/tools/Makefile.sources > > index e2451ea..e8ce891 100644 > > --- a/tools/Makefile.sources > > +++ b/tools/Makefile.sources > > @@ -13,6 +13,7 @@ tools_prog_lists = \ > > intel_bios_reader \ > > intel_display_crc \ > > intel_display_poller \ > > + intel_dp_compliance \ > > intel_forcewaked \ > > intel_gpu_frequency \ > > intel_firmware_decode \ > > @@ -56,3 +57,9 @@ intel_l3_parity_SOURCES = \ > > intel_l3_parity.h \ > > intel_l3_udev_listener.c > > > > +intel_dp_compliance_SOURCES = \ > > + intel_dp_compliance.c \ > > + intel_dp_compliance.h \ > > + intel_dp_compliance_hotplug.c \ > > + $(NULL) > > + > > diff --git a/tools/intel_dp_compliance.c b/tools/intel_dp_compliance.c > > new file mode 100644 > > index 0000000..df1ca10 > > --- /dev/null > > +++ b/tools/intel_dp_compliance.c > > @@ -0,0 +1,1104 @@ > > +/* > > + * Copyright © 2014 Intel Corporation > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a > > + * copy of this software and associated documentation files (the "Software"), > > + * to deal in the Software without restriction, including without limitation > > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > > + * and/or sell copies of the Software, and to permit persons to whom the > > + * Software is furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice (including the next > > + * paragraph) shall be included in all copies or substantial portions of the > > + * Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > > + * IN THE SOFTWARE. > > + * > > + * Displayport Compliance Testing Application > > + * > > + * This is the userspace component of the Displayport Compliance testing > > + * software required for compliance testing of the I915 Display Port driver. > > + * This must be running in order to successfully complete Display Port > > + * compliance testing. This app and the kernel code that accompanies it has been > > + * written to satify the requirements of the Displayport Link CTS 1.2 rev1.1 > > + * specification from VESA. Note that this application does not support eDP > > + * compliance testing. > > + * > > + * Compliance Testing requires several components: > > + * - A kernel build that contains the patch set for DP compliance support > > + * - A Displayport Compliance Testing appliance such as Unigraf-DPR120 > > + * - This user application > > + * - A windows host machine to run the DPR test software > > + * - Root access on the DUT due to the use of sysfs utility > > + * > > + * Test Setup: > > + * It is strongly recommended that the windows host, test appliance and DUT > > + * be freshly restarted before any testing begins to ensure that any previous > > + * configurations and settings will not interfere with test process. Refer to > > + * the test appliance documentation for setup, software installation and > > + * operation specific to that device. > > + * > > + * The Linux DUT must be in text (console) mode and cannot have any other > > + * display manager running. You must be logged in as root to run this user app. > > + * Once the user application is up and running, waiting for test requests, the > > + * software on the windows host can now be used to execute the compliance tests. > > + * > > + * This userspace application supports following tests from the DP CTS Spec > > + * Rev 1.1: > > + * - Link Training Tests: Supports tests 4.3.1.1 to 4.3.2.3 > > + * - EDID Tests: Supports EDID read (4.2.2.3),EDID Read failure and corruption > > + * detection tests (4.2.2.4, 4.2.2.5, 4.2.2.6) > > + * - Video Pattern generation tests: This supports only the 24 and 18bpp color > > + * ramp test pattern (4.3.3.1). > > + * > > + * Connections (required): > > + * - Test Appliance connected to the external Displayport connector on the DUT > > + * - Test Appliance Monitor Out connected to Displayport connector on the > > + * monitor > > + * - Test appliance connected to the Windows Host via USB > > + * > > + * Debugfs Files: > > + * The file root for all the debugfs file: > > + * /sys/kernel/debug/dri/0/ > > + * > > + * The specific files are as follows: > > + * > > + * i915_dp_test_active > > + * A simple flag that indicates whether or not compliance testing is currently > > + * active in the kernel. This flag is polled by userspace and once set, invokes > > + * the test handler in the user app. This flag is set by the test handler in the > > + * kernel after reading the registers requested by the test appliance. > > + * > > + * i915_dp_test_data > > + * Test data is used by the kernel to pass parameters to the user app. Eg: In > > + * case of EDID tests, the data that is delivered to the userspace is the video > > + * mode to be set for the test. > > + * In case of video pattern test, the data that is delivered to the userspace is > > + * the width and height of the test pattern and the bits per color value. > > + * > > + * i915_dp_test_type > > + * The test type variable instructs the user app as to what the requested test > > + * was from the sink device. These values defined at the top of the application's > > + * main implementation file must be kept in sync with the values defined in the > > + * kernel's drm_dp_helper.h file. > > + * This app is based on some prior work submitted in April 2015 by Todd Previte > > + * (<tprevite@gmail.com>) > > + * > > + * > > + * This tool can be run as: > > + * ./intel_dp_compliance It will wait till you start compliance suite from > > + * DPR 120. > > + * ./intel_dp_compliance -h This will open the help > > + * ./intel_dp_compliance -i This will provide information about current > > + * connectors/CRTCs. This can be used for debugging purpose. > > + * > > + * Authors: > > + * Manasi Navare <manasi.d.navare@intel.com> > > + * > > + * Elements of the modeset code adapted from David Herrmann's > > + * DRM modeset example > > + * > > + */ > > +#include "igt.h" > > +#include <errno.h> > > +#include <getopt.h> > > +#include <math.h> > > +#include <stdint.h> > > +#include <stdbool.h> > > +#include <strings.h> > > +#include <unistd.h> > > +#include <termios.h> > > +#include <sys/poll.h> > > +#include <sys/time.h> > > +#include <sys/ioctl.h> > > +#include <sys/types.h> > > +#include <sys/stat.h> > > +#include <sys/select.h> > > +#include <assert.h> > > +#include <signal.h> > > +#include <fcntl.h> > > +#include <time.h> > > + > > +#include "intel_dp_compliance.h" > > + > > +#include <stdlib.h> > > +#include <signal.h> > > + > > +/* User Input definitions */ > > +#define HELP_DESCRIPTION 1 > > + > > +/* Debugfs file definitions */ > > +#define INTEL_DP_TEST_TYPE_FILE "i915_dp_test_type" > > +#define INTEL_DP_TEST_ACTIVE_FILE "i915_dp_test_active" > > +#define INTEL_DP_TEST_DATA_FILE "i915_dp_test_data" > > + > > +/* DRM definitions - must be kept in sync with the DRM header */ > > +#define DP_TEST_LINK_TRAINING (1 << 0) > > +#define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) > > +#define DP_TEST_LINK_EDID_READ (1 << 2) > > +#define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ > > + > > +#define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING | \ > > + DP_TEST_LINK_VIDEO_PATTERN | \ > > + DP_TEST_LINK_EDID_READ | \ > > + DP_TEST_LINK_PHY_TEST_PATTERN) > > + > > +/* NOTE: These must be kept in sync with the definitions in intel_dp.c */ > > +#define INTEL_DP_EDID_SHIFT_MASK 0 > > +#define INTEL_DP_EDID_OK (0 << INTEL_DP_EDID_SHIFT_MASK) > > +#define INTEL_DP_EDID_CORRUPT (1 << INTEL_DP_EDID_SHIFT_MASK) > > +#define INTEL_DP_RESOLUTION_SHIFT_MASK 0 > > +#define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK) > > +#define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK) > > +#define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) > > +#define DP_COMPLIANCE_VIDEO_MODE_MASK (INTEL_DP_RESOLUTION_PREFERRED |\ > > + INTEL_DP_RESOLUTION_STANDARD |\ > > + INTEL_DP_RESOLUTION_FAILSAFE) > > + > > +/* Global file pointers for the sysfs files */ > > +FILE *test_active_fp, *test_data_fp, *test_type_fp; > > + > > +bool video_pattern_flag; > > + > > +/* Video pattern test globals */ > > +uint16_t hdisplay; > > +uint16_t vdisplay; > > +uint8_t bitdepth; > > + > > +static int tio_fd; > > +struct termios saved_tio; > > + > > +drmModeRes *resources; > > +int drm_fd, modes; > > +uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE; > > +uint32_t depth = 24, stride, bpp; > > +int specified_mode_num = -1, specified_disp_id = -1; > > +int width, height; > > +uint32_t test_crtc; > > +uint32_t test_connector_id; > > +enum { > > + INTEL_MODE_INVALID = -1, > > + INTEL_MODE_NONE = 0, > > + INTEL_MODE_PREFERRED, > > + INTEL_MODE_STANDARD, > > + INTEL_MODE_FAILSAFE, > > + INTEL_MODE_VIDEO_PATTERN_TEST > > +} intel_display_mode; > > + > > +struct test_video_pattern { > > + uint16_t hdisplay; > > + uint16_t vdisplay; > > + uint8_t bitdepth; > > + uint32_t fb; > > + uint32_t size; > > + struct igt_fb fb_pattern; > > + drmModeModeInfo mode; > > + uint32_t *pixmap; > > +}; > > + > > +struct connector { > > + uint32_t id; > > + int mode_valid; > > + drmModeModeInfo mode, mode_standard, mode_preferred, mode_failsafe; > > + drmModeConnector *connector; > > + int crtc; > > + /* Standard and preferred frame buffer*/ > > + uint32_t fb, fb_width, fb_height, fb_size; > > + uint8_t *pixmap; > > + struct igt_fb fb_video_pattern; > > + /* Failsafe framebuffer - note this is a 16-bit buffer */ > > + uint32_t failsafe_fb, failsafe_width, failsafe_height; > > + uint32_t failsafe_size; > > + uint8_t *failsafe_pixmap; > > + struct igt_fb fb_failsafe_pattern; > > + struct test_video_pattern test_pattern; > > +}; > > + > > +static void clear_test_active(void) > > +{ > > + rewind(test_active_fp); > > + fprintf(test_active_fp, "%d", 0); > > + fflush(test_active_fp); > > +} > > + > > +static void setup_debugfs_files(void) > > +{ > > + test_type_fp = igt_debugfs_fopen(INTEL_DP_TEST_TYPE_FILE, "r"); > > + igt_require(test_type_fp); > > + > > + test_data_fp = igt_debugfs_fopen(INTEL_DP_TEST_DATA_FILE, "r"); > > + igt_require(test_data_fp); > > + > > + test_active_fp = igt_debugfs_fopen(INTEL_DP_TEST_ACTIVE_FILE, "w+"); > > + igt_require(test_active_fp); > > + > > + /* Reset the active flag for safety */ > > + clear_test_active(); > > +} > > + > > +static unsigned long get_test_type(void) > > +{ > > + unsigned long test_type; > > + int ret; > > + > > + if (!test_type_fp) > > + fprintf(stderr, "Invalid test_type file\r\n"); > > + rewind(test_type_fp); > > + ret = fscanf(test_type_fp, "%02lx", &test_type); > > + if (ret < 1 || test_type <= 0) { > > + igt_warn("test_type read failed - %02lx\r\n", test_type); > > + return 0; > > + } > > + > > + return test_type; > > +} > > + > > +static unsigned long get_test_edid_data(void) > > +{ > > + unsigned long test_data; > > + int ret; > > + > > + if (!test_data_fp) > > + fprintf(stderr, "Invalid test_data file\r\n"); > > + > > + rewind(test_data_fp); > > + ret = fscanf(test_data_fp, "%lx", &test_data); > > + if (ret < 1 || test_data <= 0) { > > + igt_warn("test_data read failed - %lx\r\n", test_data); > > + return 0; > > + } > > + > > + return test_data; > > +} > > + > > +static void get_test_videopattern_data(void) > > +{ > > + int count = 0; > > + uint16_t video_pattern_value[3]; > > + char video_pattern_attribute[15]; > > + int ret; > > + > > + if (!test_data_fp) > > + fprintf(stderr, "Invalid test_data file\r\n"); > > + > > + rewind(test_data_fp); > > + while (!feof(test_data_fp) && count < 3) { > > + ret = fscanf(test_data_fp, "%s %u\n", video_pattern_attribute, > > + (unsigned int *)&video_pattern_value[count++]); > > + if (ret < 2) { > > + igt_warn("test_data read failed\n"); > > + return; > > + } > > + } > > + > > + hdisplay = video_pattern_value[0]; > > + vdisplay = video_pattern_value[1]; > > + bitdepth = video_pattern_value[2]; > > + igt_info("Hdisplay = %d\r\n", hdisplay); > > + igt_info("Vdisplay = %d\r\n", vdisplay); > > + igt_info("BitDepth = %u\r\n", bitdepth); > > + > > +} > > + > > +static int process_test_request(int test_type) > > +{ > > + int mode; > > + unsigned long test_data_edid; > > + bool valid = false; > > + switch (test_type) { > > + case DP_TEST_LINK_VIDEO_PATTERN: > > + video_pattern_flag = true; > > + get_test_videopattern_data(); > > + mode = INTEL_MODE_VIDEO_PATTERN_TEST; > > + valid = true; > > + break; > > + case DP_TEST_LINK_EDID_READ: > > + test_data_edid = get_test_edid_data(); > > + mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >> > > + INTEL_DP_RESOLUTION_SHIFT_MASK; > > + valid = true; > > + break; > > + default: > > + /* Unknown test type */ > > + fprintf(stderr, "Invalid test request, ignored.\r\n"); > > + break; > > + } > > + > > + if (valid) > > + return update_display(mode, true); > > + > > + return -1; > > +} > > + > > +static void dump_connectors_fd(int drmfd) > > +{ > > + int i, j; > > + > > + drmModeRes *mode_resources = drmModeGetResources(drmfd); > > + > > + if (!mode_resources) { > > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > > + return; > > + } > > + > > + igt_info("Connectors:\n"); > > + igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); > > + for (i = 0; i < mode_resources->count_connectors; i++) { > > + drmModeConnector *connector; > > + > > + connector = drmModeGetConnectorCurrent(drmfd, > > + mode_resources->connectors[i]); > > + if (!connector) { > > + igt_warn("Could not get connector %i: %s\n", > > + mode_resources->connectors[i], strerror(errno)); > > + continue; > > + } > > + > > + igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", > > + connector->connector_id, > > + connector->encoder_id, > > + kmstest_connector_status_str(connector->connection), > > + kmstest_connector_type_str(connector->connector_type), > > + connector->mmWidth, > > + connector->mmHeight, > > + connector->count_modes); > > + > > + if (!connector->count_modes) > > + continue; > > + > > + igt_info(" Modes:\n"); > > + igt_info(" name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n"); > > + for (j = 0; j < connector->count_modes; j++) { > > + igt_info("[%d]", j); > > + kmstest_dump_mode(&connector->modes[j]); > > + } > > + > > + drmModeFreeConnector(connector); > > + } > > + igt_info("\n"); > > + > > + drmModeFreeResources(mode_resources); > > +} > > + > > +static void dump_crtcs_fd(int drmfd) > > +{ > > + int i; > > + drmModeRes *mode_resources; > > + > > + mode_resources = drmModeGetResources(drmfd); > > + if (!mode_resources) { > > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > > + return; > > + } > > + > > + igt_info("CRTCs:\n"); > > + igt_info("id\tfb\tpos\tsize\n"); > > + for (i = 0; i < mode_resources->count_crtcs; i++) { > > + drmModeCrtc *crtc; > > + > > + crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]); > > + if (!crtc) { > > + igt_warn("Could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno)); > > + continue; > > + } > > + igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n", > > + crtc->crtc_id, > > + crtc->buffer_id, > > + crtc->x, > > + crtc->y, > > + crtc->width, > > + crtc->height); > > + > > + kmstest_dump_mode(&crtc->mode); > > + > > + drmModeFreeCrtc(crtc); > > + } > > + igt_info("\n"); > > + > > + drmModeFreeResources(mode_resources); > > +} > > + > > +static void dump_info(void) > > +{ > > + dump_connectors_fd(drm_fd); > > + dump_crtcs_fd(drm_fd); > > +} > > + > > +static int setup_framebuffers(struct connector *dp_conn) > > +{ > > + > > + dp_conn->fb = igt_create_fb(drm_fd, > > + dp_conn->fb_width, dp_conn->fb_height, > > + DRM_FORMAT_XRGB8888, > > + LOCAL_DRM_FORMAT_MOD_NONE, > > + &dp_conn->fb_video_pattern); > > + igt_assert(dp_conn->fb); > > + > > + /* Map the mapping of GEM object into the virtual address space */ > > + dp_conn->pixmap = gem_mmap__gtt(drm_fd, > > + dp_conn->fb_video_pattern.gem_handle, > > + dp_conn->fb_video_pattern.size, > > + PROT_READ | PROT_WRITE); > > + if (dp_conn->pixmap == NULL) > > + return -1; > > + > > + gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle, > > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > > + dp_conn->fb_size = dp_conn->fb_video_pattern.size; > > + > > + /* After filling the device memory with 0s it needs to be unmapped */ > > + memset(dp_conn->pixmap, 0, dp_conn->fb_size); > > + munmap(dp_conn->pixmap, dp_conn->fb_size); > > + > > + return 0; > > +} > > + > > +static int setup_failsafe_framebuffer(struct connector *dp_conn) > > +{ > > + > > + dp_conn->failsafe_fb = igt_create_fb(drm_fd, > > + dp_conn->failsafe_width, > > + dp_conn->failsafe_height, > > + DRM_FORMAT_XRGB8888, > > + LOCAL_DRM_FORMAT_MOD_NONE, > > + &dp_conn->fb_failsafe_pattern); > > + igt_assert(dp_conn->failsafe_fb); > > + > > + /* Map the mapping of GEM object into the virtual address space */ > > + dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd, > > + dp_conn->fb_failsafe_pattern.gem_handle, > > + dp_conn->fb_failsafe_pattern.size, > > + PROT_READ | PROT_WRITE); > > + if (dp_conn->failsafe_pixmap == NULL) > > + return -1; > > + > > + gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle, > > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > > + dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size; > > + > > + /* After filling the device framebuffer the mapped memory needs to be freed */ > > + memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size); > > + munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size); > > + > > + return 0; > > + > > +} > > + > > +static int setup_video_pattern_framebuffer(struct connector *dp_conn) > > +{ > > + uint32_t video_width, video_height; > > + > > + video_width = dp_conn->test_pattern.hdisplay; > > + video_height = dp_conn->test_pattern.vdisplay; > > + dp_conn->test_pattern.fb = igt_create_fb(drm_fd, > > + video_width, video_height, > > + DRM_FORMAT_XRGB8888, > > + LOCAL_DRM_FORMAT_MOD_NONE, > > + &dp_conn->test_pattern.fb_pattern); > > + igt_assert(dp_conn->test_pattern.fb); > > + > > + /* Map the mapping of GEM object into the virtual address space */ > > + dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd, > > + dp_conn->test_pattern.fb_pattern.gem_handle, > > + dp_conn->test_pattern.fb_pattern.size, > > + PROT_READ | PROT_WRITE); > > + if (dp_conn->test_pattern.pixmap == NULL) > > + return -1; > > + > > + gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle, > > + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); > > + > > + dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size; > > + > > + memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size); > > + return 0; > > + > > +} > > + > > +static int fill_framebuffer(struct connector *dp_conn) > > +{ > > + uint32_t tile_height, tile_width, video_width, video_height; > > + uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr; > > + int x, y; > > + int32_t pixel_val; > > + > > + video_width = dp_conn->test_pattern.hdisplay; > > + video_height = dp_conn->test_pattern.vdisplay; > > + > > + tile_height = 64; > > + tile_width = 1 << (dp_conn->test_pattern.bitdepth); > > + > > + red_ptr = dp_conn->test_pattern.pixmap; > > + green_ptr = red_ptr + (video_width * tile_height); > > + blue_ptr = green_ptr + (video_width * tile_height); > > + white_ptr = blue_ptr + (video_width * tile_height); > > + x = 0; > > + > > + /* Fill the frame buffer with video pattern from CTS 3.1.5 */ > > + while (x < video_width) { > > + for (pixel_val = 0; pixel_val < 256; > > + pixel_val = pixel_val + (256 / tile_width)) { > > + red_ptr[x] = pixel_val << 16; > > + green_ptr[x] = pixel_val << 8; > > + blue_ptr[x] = pixel_val << 0; > > + white_ptr[x] = red_ptr[x] | green_ptr[x] | blue_ptr[x]; > > + if (++x >= video_width) > > + break; > > + } > > + } > > + for (y = 0; y < video_height; y++) { > > + if (y == 0 || y == 64 || y == 128 || y == 192) > > + continue; > > + switch ((y / tile_height) % 4) { > > + case 0: > > + src_ptr = red_ptr; > > + break; > > + case 1: > > + src_ptr = green_ptr; > > + break; > > + case 2: > > + src_ptr = blue_ptr; > > + break; > > + case 3: > > + src_ptr = white_ptr; > > + break; > > + } > > + dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width); > > + memcpy(dst_ptr, src_ptr, (video_width * 4)); > > + } > > + munmap(dp_conn->test_pattern.pixmap, > > + dp_conn->test_pattern.size); > > + return 0; > > +} > > + > > +static int set_test_mode(struct connector *dp_conn) > > +{ > > + int ret = 0; > > + int i; > > + bool found_std = false, found_fs = false; > > + drmModeConnector *c = dp_conn->connector; > > + > > + /* Ignore any disconnected devices */ > > + if (c->connection != DRM_MODE_CONNECTED) { > > + igt_warn("Connector %u disconnected\r\n", c->connector_id); > > + return -ENOENT; > > + } > > + igt_info("Connector setup:\r\n"); > > + /* Setup preferred mode - should be mode[0] in the list */ > > + dp_conn->mode_preferred = c->modes[0]; > > + dp_conn->fb_width = c->modes[0].hdisplay; > > + dp_conn->fb_height = c->modes[0].vdisplay; > > + > > + dp_conn->test_pattern.mode = c->modes[0]; > > + dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay; > > + dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay; > > + > > + igt_info("Preferred mode (mode 0) for connector %u is %ux%u\r\n", > > + dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay); > > + fflush(stdin); > > + > > + for (i = 1; i < c->count_modes; i++) { > > + /* Standard mode is 800x600@60 */ > > + if (c->modes[i].hdisplay == 800 && > > + c->modes[i].vdisplay == 600 && > > + c->modes[i].vrefresh == 60 && > > + found_std == false) { > > + dp_conn->mode_standard = c->modes[i]; > > + igt_info("Standard mode (%d) for connector %u is %ux%u\r\n", > > + i, > > + c->connector_id, > > + c->modes[i].hdisplay, > > + c->modes[i].vdisplay); > > + found_std = true; > > + } > > + /* Failsafe mode is 640x480@60 */ > > + if (c->modes[i].hdisplay == 640 && > > + c->modes[i].vdisplay == 480 && > > + c->modes[i].vrefresh == 60 && > > + found_fs == false) { > > + dp_conn->mode_failsafe = c->modes[i]; > > + dp_conn->failsafe_width = c->modes[i].hdisplay; > > + dp_conn->failsafe_height = c->modes[i].vdisplay; > > + igt_info("Failsafe mode (%d) for connector %u is %ux%u\r\n", > > + i, > > + c->connector_id, > > + c->modes[i].hdisplay, > > + c->modes[i].vdisplay); > > + found_fs = true; > > + } > > + } > > + > > + ret = setup_framebuffers(dp_conn); > > + if (ret) { > > + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", > > + c->connector_id, ret); > > + return ret; > > + } > > + > > + if (found_fs) { > > + ret = setup_failsafe_framebuffer(dp_conn); > > + if (ret) { > > + igt_warn("Creating failsafe framebuffer for connector %u failed (%d)\r\n", > > + c->connector_id, ret); > > + return ret; > > + } > > + } > > + > > + if (video_pattern_flag) { > > + dp_conn->test_pattern.hdisplay = hdisplay; > > + dp_conn->test_pattern.vdisplay = vdisplay; > > + dp_conn->test_pattern.bitdepth = bitdepth; > > + > > + ret = setup_video_pattern_framebuffer(dp_conn); > > + if (ret) { > > + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", > > + c->connector_id, ret); > > + return ret; > > + } > > + > > + ret = fill_framebuffer(dp_conn); > > + if (ret) { > > + igt_warn("Filling framebuffer for connector %u failed (%d)\r\n", > > + c->connector_id, ret); > > + return ret; > > + } > > + } > > + > > + return ret; > > +} > > + > > +static int set_video(int mode, struct connector *test_connector) > > +{ > > + drmModeModeInfo *requested_mode; > > + uint32_t required_fb_id; > > + struct igt_fb required_fb; > > + int ret = 0; > > + > > + switch (mode) { > > + case INTEL_MODE_NONE: > > + igt_info("NONE\r\n"); > > + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, > > + -1, 0, 0, NULL, 0, NULL); > > + goto out; > > + case INTEL_MODE_PREFERRED: > > + igt_info("PREFERRED\r\n"); > > + requested_mode = &test_connector->mode_preferred; > > + required_fb_id = test_connector->fb; > > + required_fb = test_connector->fb_video_pattern; > > + break; > > + case INTEL_MODE_STANDARD: > > + igt_info("STANDARD\r\n"); > > + requested_mode = &test_connector->mode_standard; > > + required_fb_id = test_connector->fb; > > + required_fb = test_connector->fb_video_pattern; > > + break; > > + case INTEL_MODE_FAILSAFE: > > + igt_info("FAILSAFE\r\n"); > > + requested_mode = &test_connector->mode_failsafe; > > + required_fb_id = test_connector->failsafe_fb; > > + required_fb = test_connector->fb_failsafe_pattern; > > + break; > > + case INTEL_MODE_VIDEO_PATTERN_TEST: > > + igt_info("VIDEO PATTERN TEST\r\n"); > > + requested_mode = &test_connector->test_pattern.mode; > > + required_fb_id = test_connector->test_pattern.fb; > > + required_fb = test_connector->test_pattern.fb_pattern; > > + break; > > + case INTEL_MODE_INVALID: > > + default: > > + igt_warn("INVALID! (%08x) Mode set aborted!\r\n", mode); > > + return -1; > > + } > > + > > + igt_info("CRTC(%u):", test_connector->crtc); > > + kmstest_dump_mode(requested_mode); > > + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0, > > + &test_connector->id, 1, requested_mode); > > + if (ret) { > > + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", > > + requested_mode->hdisplay, requested_mode->vdisplay, > > + requested_mode->vrefresh, strerror(errno)); > > + igt_remove_fb(drm_fd, &required_fb); > > + > > + } > > + /* Keep the pattern on output lines for 1 sec for DPR-120 to detect it */ > > + sleep(1); > > + > > +out: > > + if (ret) { > > + igt_warn("Failed to set CRTC for connector %u\r\n", > > + test_connector->id); > > + } > > + > > + return ret; > > +} > > + > > +static int > > +set_default_mode(struct connector *c, bool set_mode) > > +{ > > + unsigned int fb_id = 0; > > + struct igt_fb fb_info; > > + int ret = 0; > > + > > + if (!set_mode) { > > + ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0, > > + NULL, 0, NULL); > > + if (ret) > > + igt_warn("Failed to unset mode"); > > + return ret; > > + } > > + > > + c->mode = c->connector->modes[0]; > > + > > + width = c->mode.hdisplay; > > + height = c->mode.vdisplay; > > + > > + fb_id = igt_create_pattern_fb(drm_fd, width, height, > > + DRM_FORMAT_XRGB8888, > > + tiling, &fb_info); > > + > > + igt_info("CRTC(%u):[%d]", c->crtc, 0); > > + kmstest_dump_mode(&c->mode); > > + drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL); > > + ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, > > + &c->id, 1, &c->mode); > > + if (ret) { > > + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", > > + width, height, c->mode.vrefresh, strerror(errno)); > > + igt_remove_fb(drm_fd, &fb_info); > > + > > + } > > + > > + return ret; > > +} > > + > > +static uint32_t find_crtc_for_connector(drmModeConnector *c) > > +{ > > + drmModeEncoder *e; > > + uint32_t possible_crtcs; > > + int i, j; > > + > > + for (i = 0; i < c->count_encoders; i++) { > > + e = drmModeGetEncoder(drm_fd, c->encoders[i]); > > + possible_crtcs = e->possible_crtcs; > > + drmModeFreeEncoder(e); > > + > > + for (j = 0; possible_crtcs >> j; j++) > > + if (possible_crtcs & (1 << j)) > > + return resources->crtcs[j]; > > + } > > + return 0; > > +} > > + > > +/* > > + * Re-probe connectors and do a modeset based on test request or > > + * in case of a hotplug uevent. > > + * > > + * @mode: Video mode requested by the test > > + * @is_compliance_test: 1: If it is a compliance test > > + * 0: If it is a hotplug event > > + * > > + * Returns: > > + * 0: On Success > > + * -1: On failure > > + */ > > +int update_display(int mode, bool is_compliance_test) > > +{ > > + struct connector *connectors, *conn; > > + int cnt, ret = 0; > > + bool set_mode; > > + > > + resources = drmModeGetResources(drm_fd); > > + if (!resources) { > > + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); > > + return -1; > > + } > > + > > + connectors = calloc(resources->count_connectors, > > + sizeof(struct connector)); > > + if (!connectors) > > + return -1; > > + > > + /* Find any connected displays */ > > + for (cnt = 0; cnt < resources->count_connectors; cnt++) { > > + drmModeConnector *c; > > + > > + conn = &connectors[cnt]; > > + conn->id = resources->connectors[cnt]; > > + c = drmModeGetConnector(drm_fd, conn->id); > > + if (c->connector_type == DRM_MODE_CONNECTOR_DisplayPort && > > + c->connection == DRM_MODE_CONNECTED) { > > + test_connector_id = c->connector_id; > > + conn->connector = c; > > + conn->crtc = find_crtc_for_connector(c); > > + test_crtc = conn->crtc; > > + set_mode = true; > > + break; > > + } else if (c->connector_id == test_connector_id && > > + c->connection == DRM_MODE_DISCONNECTED) { > > + conn->connector = c; > > + conn->crtc = test_crtc; > > + set_mode = false; > > + break; > > + } > > + } > > + > > + if (cnt == resources->count_connectors) { > > + ret = -1; > > + goto err; > > + } > > + > > + if (is_compliance_test) { > > + set_test_mode(conn); > > + ret = set_video(INTEL_MODE_NONE, conn); > > + ret = set_video(mode, conn); > > + > > + } else > > + ret = set_default_mode(conn, set_mode); > > + > > + err: > > + drmModeFreeConnector(conn->connector); > > + /* Error condition if no connected displays */ > > + free(connectors); > > + drmModeFreeResources(resources); > > + return ret; > > +} > > + > > +static const char optstr[] = "hi"; > > + > > +static void __attribute__((noreturn)) usage(char *name, char opt) > > +{ > > + igt_info("usage: %s [-hi]\n", name); > > + igt_info("\t-i\tdump info\n"); > > + igt_info("\tDefault is to respond to DPR-120 tests\n"); > > + exit((opt != 'h') ? -1 : 0); > > +} > > + > > +static void cleanup_debugfs(void) > > +{ > > + fclose(test_active_fp); > > + fclose(test_data_fp); > > + fclose(test_type_fp); > > +} > > + > > +static void __attribute__((noreturn)) cleanup_and_exit(int ret) > > +{ > > + cleanup_debugfs(); > > + close(drm_fd); > > + igt_info("Compliance testing application exiting\n"); > > + exit(ret); > > +} > > + > > +static void cleanup_test(void) > > +{ > > + video_pattern_flag = false; > > + hdisplay = 0; > > + vdisplay = 0; > > + bitdepth = 0; > > +} > > + > > +static void read_test_request(void) > > +{ > > + unsigned long test_type; > > + > > + test_type = get_test_type(); > > + process_test_request(test_type); > > + cleanup_test(); > > + clear_test_active(); > > +} > > + > > +static gboolean test_handler(GIOChannel *source, GIOCondition condition, > > + gpointer data) > > +{ > > + unsigned long test_active; > > + int ret; > > + > > + rewind(test_active_fp); > > + > > + ret = fscanf(test_active_fp, "%lx", &test_active); > > + if (ret < 1) > > + return FALSE; > > + > > + if (test_active) > > + read_test_request(); > > + return TRUE; > > +} > > + > > +static gboolean input_event(GIOChannel *source, GIOCondition condition, > > + gpointer data) > > +{ > > + gchar buf[2]; > > + gsize count; > > + > > + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf)); > > + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) { > > + cleanup_and_exit(0); > > + } > > + > > + return TRUE; > > +} > > + > > +static void enter_exec_path(char **argv) > > +{ > > + char *exec_path = NULL; > > + char *pos = NULL; > > + short len_path = 0; > > + int ret; > > + > > + len_path = strlen(argv[0]); > > + exec_path = (char *) malloc(len_path); > > + > > + memcpy(exec_path, argv[0], len_path); > > + pos = strrchr(exec_path, '/'); > > + if (pos != NULL) > > + *(pos+1) = '\0'; > > + > > + ret = chdir(exec_path); > > + igt_assert_eq(ret, 0); > > + free(exec_path); > > +} > > + > > +static void restore_termio_mode(int sig) > > +{ > > + tcsetattr(tio_fd, TCSANOW, &saved_tio); > > + close(tio_fd); > > +} > > + > > +static void set_termio_mode(void) > > +{ > > + struct termios tio; > > + > > + /* don't attempt to set terminal attributes if not in the foreground > > + * process group > > + */ > > + if (getpgrp() != tcgetpgrp(STDOUT_FILENO)) > > + return; > > + > > + tio_fd = dup(STDIN_FILENO); > > + tcgetattr(tio_fd, &saved_tio); > > + igt_install_exit_handler(restore_termio_mode); > > + tio = saved_tio; > > + tio.c_lflag &= ~(ICANON | ECHO); > > + tcsetattr(tio_fd, TCSANOW, &tio); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int c; > > + int ret = 0; > > + GIOChannel *stdinchannel, *testactive_channel; > > + GMainLoop *mainloop; > > + bool opt_dump_info = false; > > + struct option long_opts[] = { > > + {"help-description", 0, 0, HELP_DESCRIPTION}, > > + {"help", 0, 0, 'h'}, > > + }; > > + > > + igt_skip_on_simulation(); > > + > > + enter_exec_path(argv); > > + > > + while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) { > > + switch (c) { > > + case 'i': > > + opt_dump_info = true; > > + break; > > + case HELP_DESCRIPTION: > > + igt_info("DP Compliance Test Suite using DPR-120\n"); > > + igt_info("EDID tests\n"); > > + igt_info("Video Pattern Generation tests\n"); > > + exit(0); > > + break; > > + default: > > + /* fall through */ > > + case 'h': > > + usage(argv[0], c); > > + break; > > + } > > + } > > + > > + set_termio_mode(); > > + > > + igt_info("*************DP Compliance Testing using DPR-120*************\n"); > > + igt_info("Waiting for test request......\n"); > > + drm_fd = drm_open_driver(DRIVER_ANY); > > + > > + kmstest_set_vt_graphics_mode(); > > + setup_debugfs_files(); > > + cleanup_test(); > > + > > + if (opt_dump_info) { > > + dump_info(); > > + goto out_close; > > + } > > + > > + /* Get the DP connector ID and CRTC */ > > + if (update_display(0, false)) { > > + igt_warn("Failed to set default mode\n"); > > + ret = -1; > > + goto out_close; > > + } > > + > > + mainloop = g_main_loop_new(NULL, FALSE); > > + if (!mainloop) { > > + igt_warn("Failed to create GMainLoop\n"); > > + ret = -1; > > + goto out_close; > > + } > > + > > + if (!intel_dp_compliance_setup_hotplug()) { > > + igt_warn("Failed to initialize hotplug support\n"); > > + goto out_mainloop; > > + } > > + > > + testactive_channel = g_io_channel_unix_new(fileno(test_active_fp)); > > + if (!testactive_channel) { > > + igt_warn("Failed to create test_active GIOChannel\n"); > > + goto out_close; > > + } > > + > > + ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR, > > + test_handler, NULL); > > + if (ret < 0) { > > + igt_warn("Failed to add watch on udev GIOChannel\n"); > > + goto out_close; > > + } > > + > > + stdinchannel = g_io_channel_unix_new(0); > > + if (!stdinchannel) { > > + igt_warn("Failed to create stdin GIOChannel\n"); > > + goto out_hotplug; > > + } > > + > > + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event, > > + NULL); > > + if (ret < 0) { > > + igt_warn("Failed to add watch on stdin GIOChannel\n"); > > + goto out_stdio; > > + } > > + > > + ret = 0; > > + > > + g_main_loop_run(mainloop); > > + > > +out_stdio: > > + g_io_channel_shutdown(stdinchannel, TRUE, NULL); > > +out_hotplug: > > + intel_dp_compliance_cleanup_hotplug(); > > +out_mainloop: > > + g_main_loop_unref(mainloop); > > +out_close: > > + cleanup_debugfs(); > > + close(drm_fd); > > + > > + igt_assert_eq(ret, 0); > > + > > + igt_info("Compliance testing application exiting\n"); > > + igt_exit(); > > +} > > diff --git a/tools/intel_dp_compliance.h b/tools/intel_dp_compliance.h > > new file mode 100644 > > index 0000000..ade1e2f > > --- /dev/null > > +++ b/tools/intel_dp_compliance.h > > @@ -0,0 +1,35 @@ > > +/* > > + * Copyright 2010 Intel Corporation > > + * Manasi Navare <manasi.d.navare@intel.com> > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a > > + * copy of this software and associated documentation files (the "Software"), > > + * to deal in the Software without restriction, including without limitation > > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > > + * and/or sell copies of the Software, and to permit persons to whom the > > + * Software is furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > > + * IN THE SOFTWARE. > > + */ > > + > > +#include <stdio.h> > > +#include <string.h> > > +#include <stdlib.h> > > +#include <glib.h> > > + > > +extern int drm_fd; > > + > > +gboolean intel_dp_compliance_setup_hotplug(void); > > +void intel_dp_compliance_cleanup_hotplug(void); > > + > > +/* called by the hotplug code */ > > +int update_display(int mode, bool is_compliance_test); > > diff --git a/tools/intel_dp_compliance_hotplug.c b/tools/intel_dp_compliance_hotplug.c > > new file mode 100644 > > index 0000000..7c7ea65 > > --- /dev/null > > +++ b/tools/intel_dp_compliance_hotplug.c > > @@ -0,0 +1,123 @@ > > +/* > > + * Copyright 2010 Intel Corporation > > + * Jesse Barnes <jesse.barnes@intel.com> > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a > > + * copy of this software and associated documentation files (the "Software"), > > + * to deal in the Software without restriction, including without limitation > > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > > + * and/or sell copies of the Software, and to permit persons to whom the > > + * Software is furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > > + * IN THE SOFTWARE. > > + */ > > + > > +#include "igt.h" > > +#include <stdio.h> > > +#include <string.h> > > +#include <stdlib.h> > > + > > +#include <sys/stat.h> > > + > > +#include "intel_dp_compliance.h" > > +#include <libudev.h> > > +static struct udev_monitor *uevent_monitor; > > +static struct udev *udev; > > +static GIOChannel *udevchannel; > > + > > +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition, > > + gpointer data) > > +{ > > + struct udev_device *dev; > > + dev_t udev_devnum; > > + struct stat s; > > + const char *hotplug; > > + > > + dev = udev_monitor_receive_device(uevent_monitor); > > + if (!dev) > > + goto out; > > + > > + udev_devnum = udev_device_get_devnum(dev); > > + fstat(drm_fd, &s); > > + > > + hotplug = udev_device_get_property_value(dev, "HOTPLUG"); > > + > > + if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 && > > + hotplug && atoi(hotplug) == 1) > > + update_display(0, false); > > + > > + udev_device_unref(dev); > > +out: > > + return TRUE; > > +} > > + > > + > > +gboolean intel_dp_compliance_setup_hotplug(void) > > +{ > > + int ret; > > + > > + udev = udev_new(); > > + if (!udev) { > > + igt_warn("Failed to create udev object\n"); > > + goto out; > > + } > > + > > + uevent_monitor = udev_monitor_new_from_netlink(udev, "udev"); > > + if (!uevent_monitor) { > > + igt_warn("Failed to create udev event monitor\n"); > > + goto out; > > + } > > + > > + ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor, > > + "drm", > > + "drm_minor"); > > + if (ret < 0) { > > + igt_warn("Failed to filter for drm events\n"); > > + goto out; > > + } > > + > > + ret = udev_monitor_enable_receiving(uevent_monitor); > > + if (ret < 0) { > > + igt_warn("Failed to enable udev event reception\n"); > > + goto out; > > + } > > + > > + udevchannel = > > + g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor)); > > + if (!udevchannel) { > > + igt_warn("Failed to create udev GIOChannel\n"); > > + goto out; > > + } > > + > > + ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event, > > + udev); > > + if (ret < 0) { > > + igt_warn("Failed to add watch on udev GIOChannel\n"); > > + goto out; > > + } > > + > > + return TRUE; > > + > > +out: > > + intel_dp_compliance_cleanup_hotplug(); > > + return FALSE; > > +} > > + > > +void intel_dp_compliance_cleanup_hotplug(void) > > +{ > > + if (udevchannel) > > + g_io_channel_shutdown(udevchannel, TRUE, NULL); > > + if (uevent_monitor) > > + udev_monitor_unref(uevent_monitor); > > + if (udev) > > + udev_unref(udev); > > +} > > -- > > 2.7.4 > >
diff --git a/tools/Makefile.am b/tools/Makefile.am index 18f86f6..bd8f512 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -16,6 +16,7 @@ AM_CFLAGS = $(DEBUG_CFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) \ LDADD = $(top_builddir)/lib/libintel_tools.la AM_LDFLAGS = -Wl,--as-needed +intel_dp_compliance_LDADD = $(top_builddir)/lib/libintel_tools.la $(GLIB_LIBS) # aubdumper diff --git a/tools/Makefile.sources b/tools/Makefile.sources index e2451ea..e8ce891 100644 --- a/tools/Makefile.sources +++ b/tools/Makefile.sources @@ -13,6 +13,7 @@ tools_prog_lists = \ intel_bios_reader \ intel_display_crc \ intel_display_poller \ + intel_dp_compliance \ intel_forcewaked \ intel_gpu_frequency \ intel_firmware_decode \ @@ -56,3 +57,9 @@ intel_l3_parity_SOURCES = \ intel_l3_parity.h \ intel_l3_udev_listener.c +intel_dp_compliance_SOURCES = \ + intel_dp_compliance.c \ + intel_dp_compliance.h \ + intel_dp_compliance_hotplug.c \ + $(NULL) + diff --git a/tools/intel_dp_compliance.c b/tools/intel_dp_compliance.c new file mode 100644 index 0000000..df1ca10 --- /dev/null +++ b/tools/intel_dp_compliance.c @@ -0,0 +1,1104 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Displayport Compliance Testing Application + * + * This is the userspace component of the Displayport Compliance testing + * software required for compliance testing of the I915 Display Port driver. + * This must be running in order to successfully complete Display Port + * compliance testing. This app and the kernel code that accompanies it has been + * written to satify the requirements of the Displayport Link CTS 1.2 rev1.1 + * specification from VESA. Note that this application does not support eDP + * compliance testing. + * + * Compliance Testing requires several components: + * - A kernel build that contains the patch set for DP compliance support + * - A Displayport Compliance Testing appliance such as Unigraf-DPR120 + * - This user application + * - A windows host machine to run the DPR test software + * - Root access on the DUT due to the use of sysfs utility + * + * Test Setup: + * It is strongly recommended that the windows host, test appliance and DUT + * be freshly restarted before any testing begins to ensure that any previous + * configurations and settings will not interfere with test process. Refer to + * the test appliance documentation for setup, software installation and + * operation specific to that device. + * + * The Linux DUT must be in text (console) mode and cannot have any other + * display manager running. You must be logged in as root to run this user app. + * Once the user application is up and running, waiting for test requests, the + * software on the windows host can now be used to execute the compliance tests. + * + * This userspace application supports following tests from the DP CTS Spec + * Rev 1.1: + * - Link Training Tests: Supports tests 4.3.1.1 to 4.3.2.3 + * - EDID Tests: Supports EDID read (4.2.2.3),EDID Read failure and corruption + * detection tests (4.2.2.4, 4.2.2.5, 4.2.2.6) + * - Video Pattern generation tests: This supports only the 24 and 18bpp color + * ramp test pattern (4.3.3.1). + * + * Connections (required): + * - Test Appliance connected to the external Displayport connector on the DUT + * - Test Appliance Monitor Out connected to Displayport connector on the + * monitor + * - Test appliance connected to the Windows Host via USB + * + * Debugfs Files: + * The file root for all the debugfs file: + * /sys/kernel/debug/dri/0/ + * + * The specific files are as follows: + * + * i915_dp_test_active + * A simple flag that indicates whether or not compliance testing is currently + * active in the kernel. This flag is polled by userspace and once set, invokes + * the test handler in the user app. This flag is set by the test handler in the + * kernel after reading the registers requested by the test appliance. + * + * i915_dp_test_data + * Test data is used by the kernel to pass parameters to the user app. Eg: In + * case of EDID tests, the data that is delivered to the userspace is the video + * mode to be set for the test. + * In case of video pattern test, the data that is delivered to the userspace is + * the width and height of the test pattern and the bits per color value. + * + * i915_dp_test_type + * The test type variable instructs the user app as to what the requested test + * was from the sink device. These values defined at the top of the application's + * main implementation file must be kept in sync with the values defined in the + * kernel's drm_dp_helper.h file. + * This app is based on some prior work submitted in April 2015 by Todd Previte + * (<tprevite@gmail.com>) + * + * + * This tool can be run as: + * ./intel_dp_compliance It will wait till you start compliance suite from + * DPR 120. + * ./intel_dp_compliance -h This will open the help + * ./intel_dp_compliance -i This will provide information about current + * connectors/CRTCs. This can be used for debugging purpose. + * + * Authors: + * Manasi Navare <manasi.d.navare@intel.com> + * + * Elements of the modeset code adapted from David Herrmann's + * DRM modeset example + * + */ +#include "igt.h" +#include <errno.h> +#include <getopt.h> +#include <math.h> +#include <stdint.h> +#include <stdbool.h> +#include <strings.h> +#include <unistd.h> +#include <termios.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <assert.h> +#include <signal.h> +#include <fcntl.h> +#include <time.h> + +#include "intel_dp_compliance.h" + +#include <stdlib.h> +#include <signal.h> + +/* User Input definitions */ +#define HELP_DESCRIPTION 1 + +/* Debugfs file definitions */ +#define INTEL_DP_TEST_TYPE_FILE "i915_dp_test_type" +#define INTEL_DP_TEST_ACTIVE_FILE "i915_dp_test_active" +#define INTEL_DP_TEST_DATA_FILE "i915_dp_test_data" + +/* DRM definitions - must be kept in sync with the DRM header */ +#define DP_TEST_LINK_TRAINING (1 << 0) +#define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) +#define DP_TEST_LINK_EDID_READ (1 << 2) +#define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ + +#define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING | \ + DP_TEST_LINK_VIDEO_PATTERN | \ + DP_TEST_LINK_EDID_READ | \ + DP_TEST_LINK_PHY_TEST_PATTERN) + +/* NOTE: These must be kept in sync with the definitions in intel_dp.c */ +#define INTEL_DP_EDID_SHIFT_MASK 0 +#define INTEL_DP_EDID_OK (0 << INTEL_DP_EDID_SHIFT_MASK) +#define INTEL_DP_EDID_CORRUPT (1 << INTEL_DP_EDID_SHIFT_MASK) +#define INTEL_DP_RESOLUTION_SHIFT_MASK 0 +#define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK) +#define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK) +#define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) +#define DP_COMPLIANCE_VIDEO_MODE_MASK (INTEL_DP_RESOLUTION_PREFERRED |\ + INTEL_DP_RESOLUTION_STANDARD |\ + INTEL_DP_RESOLUTION_FAILSAFE) + +/* Global file pointers for the sysfs files */ +FILE *test_active_fp, *test_data_fp, *test_type_fp; + +bool video_pattern_flag; + +/* Video pattern test globals */ +uint16_t hdisplay; +uint16_t vdisplay; +uint8_t bitdepth; + +static int tio_fd; +struct termios saved_tio; + +drmModeRes *resources; +int drm_fd, modes; +uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE; +uint32_t depth = 24, stride, bpp; +int specified_mode_num = -1, specified_disp_id = -1; +int width, height; +uint32_t test_crtc; +uint32_t test_connector_id; +enum { + INTEL_MODE_INVALID = -1, + INTEL_MODE_NONE = 0, + INTEL_MODE_PREFERRED, + INTEL_MODE_STANDARD, + INTEL_MODE_FAILSAFE, + INTEL_MODE_VIDEO_PATTERN_TEST +} intel_display_mode; + +struct test_video_pattern { + uint16_t hdisplay; + uint16_t vdisplay; + uint8_t bitdepth; + uint32_t fb; + uint32_t size; + struct igt_fb fb_pattern; + drmModeModeInfo mode; + uint32_t *pixmap; +}; + +struct connector { + uint32_t id; + int mode_valid; + drmModeModeInfo mode, mode_standard, mode_preferred, mode_failsafe; + drmModeConnector *connector; + int crtc; + /* Standard and preferred frame buffer*/ + uint32_t fb, fb_width, fb_height, fb_size; + uint8_t *pixmap; + struct igt_fb fb_video_pattern; + /* Failsafe framebuffer - note this is a 16-bit buffer */ + uint32_t failsafe_fb, failsafe_width, failsafe_height; + uint32_t failsafe_size; + uint8_t *failsafe_pixmap; + struct igt_fb fb_failsafe_pattern; + struct test_video_pattern test_pattern; +}; + +static void clear_test_active(void) +{ + rewind(test_active_fp); + fprintf(test_active_fp, "%d", 0); + fflush(test_active_fp); +} + +static void setup_debugfs_files(void) +{ + test_type_fp = igt_debugfs_fopen(INTEL_DP_TEST_TYPE_FILE, "r"); + igt_require(test_type_fp); + + test_data_fp = igt_debugfs_fopen(INTEL_DP_TEST_DATA_FILE, "r"); + igt_require(test_data_fp); + + test_active_fp = igt_debugfs_fopen(INTEL_DP_TEST_ACTIVE_FILE, "w+"); + igt_require(test_active_fp); + + /* Reset the active flag for safety */ + clear_test_active(); +} + +static unsigned long get_test_type(void) +{ + unsigned long test_type; + int ret; + + if (!test_type_fp) + fprintf(stderr, "Invalid test_type file\r\n"); + rewind(test_type_fp); + ret = fscanf(test_type_fp, "%02lx", &test_type); + if (ret < 1 || test_type <= 0) { + igt_warn("test_type read failed - %02lx\r\n", test_type); + return 0; + } + + return test_type; +} + +static unsigned long get_test_edid_data(void) +{ + unsigned long test_data; + int ret; + + if (!test_data_fp) + fprintf(stderr, "Invalid test_data file\r\n"); + + rewind(test_data_fp); + ret = fscanf(test_data_fp, "%lx", &test_data); + if (ret < 1 || test_data <= 0) { + igt_warn("test_data read failed - %lx\r\n", test_data); + return 0; + } + + return test_data; +} + +static void get_test_videopattern_data(void) +{ + int count = 0; + uint16_t video_pattern_value[3]; + char video_pattern_attribute[15]; + int ret; + + if (!test_data_fp) + fprintf(stderr, "Invalid test_data file\r\n"); + + rewind(test_data_fp); + while (!feof(test_data_fp) && count < 3) { + ret = fscanf(test_data_fp, "%s %u\n", video_pattern_attribute, + (unsigned int *)&video_pattern_value[count++]); + if (ret < 2) { + igt_warn("test_data read failed\n"); + return; + } + } + + hdisplay = video_pattern_value[0]; + vdisplay = video_pattern_value[1]; + bitdepth = video_pattern_value[2]; + igt_info("Hdisplay = %d\r\n", hdisplay); + igt_info("Vdisplay = %d\r\n", vdisplay); + igt_info("BitDepth = %u\r\n", bitdepth); + +} + +static int process_test_request(int test_type) +{ + int mode; + unsigned long test_data_edid; + bool valid = false; + switch (test_type) { + case DP_TEST_LINK_VIDEO_PATTERN: + video_pattern_flag = true; + get_test_videopattern_data(); + mode = INTEL_MODE_VIDEO_PATTERN_TEST; + valid = true; + break; + case DP_TEST_LINK_EDID_READ: + test_data_edid = get_test_edid_data(); + mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >> + INTEL_DP_RESOLUTION_SHIFT_MASK; + valid = true; + break; + default: + /* Unknown test type */ + fprintf(stderr, "Invalid test request, ignored.\r\n"); + break; + } + + if (valid) + return update_display(mode, true); + + return -1; +} + +static void dump_connectors_fd(int drmfd) +{ + int i, j; + + drmModeRes *mode_resources = drmModeGetResources(drmfd); + + if (!mode_resources) { + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); + return; + } + + igt_info("Connectors:\n"); + igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); + for (i = 0; i < mode_resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnectorCurrent(drmfd, + mode_resources->connectors[i]); + if (!connector) { + igt_warn("Could not get connector %i: %s\n", + mode_resources->connectors[i], strerror(errno)); + continue; + } + + igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", + connector->connector_id, + connector->encoder_id, + kmstest_connector_status_str(connector->connection), + kmstest_connector_type_str(connector->connector_type), + connector->mmWidth, + connector->mmHeight, + connector->count_modes); + + if (!connector->count_modes) + continue; + + igt_info(" Modes:\n"); + igt_info(" name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n"); + for (j = 0; j < connector->count_modes; j++) { + igt_info("[%d]", j); + kmstest_dump_mode(&connector->modes[j]); + } + + drmModeFreeConnector(connector); + } + igt_info("\n"); + + drmModeFreeResources(mode_resources); +} + +static void dump_crtcs_fd(int drmfd) +{ + int i; + drmModeRes *mode_resources; + + mode_resources = drmModeGetResources(drmfd); + if (!mode_resources) { + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); + return; + } + + igt_info("CRTCs:\n"); + igt_info("id\tfb\tpos\tsize\n"); + for (i = 0; i < mode_resources->count_crtcs; i++) { + drmModeCrtc *crtc; + + crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]); + if (!crtc) { + igt_warn("Could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno)); + continue; + } + igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, + crtc->y, + crtc->width, + crtc->height); + + kmstest_dump_mode(&crtc->mode); + + drmModeFreeCrtc(crtc); + } + igt_info("\n"); + + drmModeFreeResources(mode_resources); +} + +static void dump_info(void) +{ + dump_connectors_fd(drm_fd); + dump_crtcs_fd(drm_fd); +} + +static int setup_framebuffers(struct connector *dp_conn) +{ + + dp_conn->fb = igt_create_fb(drm_fd, + dp_conn->fb_width, dp_conn->fb_height, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + &dp_conn->fb_video_pattern); + igt_assert(dp_conn->fb); + + /* Map the mapping of GEM object into the virtual address space */ + dp_conn->pixmap = gem_mmap__gtt(drm_fd, + dp_conn->fb_video_pattern.gem_handle, + dp_conn->fb_video_pattern.size, + PROT_READ | PROT_WRITE); + if (dp_conn->pixmap == NULL) + return -1; + + gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + dp_conn->fb_size = dp_conn->fb_video_pattern.size; + + /* After filling the device memory with 0s it needs to be unmapped */ + memset(dp_conn->pixmap, 0, dp_conn->fb_size); + munmap(dp_conn->pixmap, dp_conn->fb_size); + + return 0; +} + +static int setup_failsafe_framebuffer(struct connector *dp_conn) +{ + + dp_conn->failsafe_fb = igt_create_fb(drm_fd, + dp_conn->failsafe_width, + dp_conn->failsafe_height, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + &dp_conn->fb_failsafe_pattern); + igt_assert(dp_conn->failsafe_fb); + + /* Map the mapping of GEM object into the virtual address space */ + dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd, + dp_conn->fb_failsafe_pattern.gem_handle, + dp_conn->fb_failsafe_pattern.size, + PROT_READ | PROT_WRITE); + if (dp_conn->failsafe_pixmap == NULL) + return -1; + + gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size; + + /* After filling the device framebuffer the mapped memory needs to be freed */ + memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size); + munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size); + + return 0; + +} + +static int setup_video_pattern_framebuffer(struct connector *dp_conn) +{ + uint32_t video_width, video_height; + + video_width = dp_conn->test_pattern.hdisplay; + video_height = dp_conn->test_pattern.vdisplay; + dp_conn->test_pattern.fb = igt_create_fb(drm_fd, + video_width, video_height, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + &dp_conn->test_pattern.fb_pattern); + igt_assert(dp_conn->test_pattern.fb); + + /* Map the mapping of GEM object into the virtual address space */ + dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd, + dp_conn->test_pattern.fb_pattern.gem_handle, + dp_conn->test_pattern.fb_pattern.size, + PROT_READ | PROT_WRITE); + if (dp_conn->test_pattern.pixmap == NULL) + return -1; + + gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + + dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size; + + memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size); + return 0; + +} + +static int fill_framebuffer(struct connector *dp_conn) +{ + uint32_t tile_height, tile_width, video_width, video_height; + uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr; + int x, y; + int32_t pixel_val; + + video_width = dp_conn->test_pattern.hdisplay; + video_height = dp_conn->test_pattern.vdisplay; + + tile_height = 64; + tile_width = 1 << (dp_conn->test_pattern.bitdepth); + + red_ptr = dp_conn->test_pattern.pixmap; + green_ptr = red_ptr + (video_width * tile_height); + blue_ptr = green_ptr + (video_width * tile_height); + white_ptr = blue_ptr + (video_width * tile_height); + x = 0; + + /* Fill the frame buffer with video pattern from CTS 3.1.5 */ + while (x < video_width) { + for (pixel_val = 0; pixel_val < 256; + pixel_val = pixel_val + (256 / tile_width)) { + red_ptr[x] = pixel_val << 16; + green_ptr[x] = pixel_val << 8; + blue_ptr[x] = pixel_val << 0; + white_ptr[x] = red_ptr[x] | green_ptr[x] | blue_ptr[x]; + if (++x >= video_width) + break; + } + } + for (y = 0; y < video_height; y++) { + if (y == 0 || y == 64 || y == 128 || y == 192) + continue; + switch ((y / tile_height) % 4) { + case 0: + src_ptr = red_ptr; + break; + case 1: + src_ptr = green_ptr; + break; + case 2: + src_ptr = blue_ptr; + break; + case 3: + src_ptr = white_ptr; + break; + } + dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width); + memcpy(dst_ptr, src_ptr, (video_width * 4)); + } + munmap(dp_conn->test_pattern.pixmap, + dp_conn->test_pattern.size); + return 0; +} + +static int set_test_mode(struct connector *dp_conn) +{ + int ret = 0; + int i; + bool found_std = false, found_fs = false; + drmModeConnector *c = dp_conn->connector; + + /* Ignore any disconnected devices */ + if (c->connection != DRM_MODE_CONNECTED) { + igt_warn("Connector %u disconnected\r\n", c->connector_id); + return -ENOENT; + } + igt_info("Connector setup:\r\n"); + /* Setup preferred mode - should be mode[0] in the list */ + dp_conn->mode_preferred = c->modes[0]; + dp_conn->fb_width = c->modes[0].hdisplay; + dp_conn->fb_height = c->modes[0].vdisplay; + + dp_conn->test_pattern.mode = c->modes[0]; + dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay; + dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay; + + igt_info("Preferred mode (mode 0) for connector %u is %ux%u\r\n", + dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay); + fflush(stdin); + + for (i = 1; i < c->count_modes; i++) { + /* Standard mode is 800x600@60 */ + if (c->modes[i].hdisplay == 800 && + c->modes[i].vdisplay == 600 && + c->modes[i].vrefresh == 60 && + found_std == false) { + dp_conn->mode_standard = c->modes[i]; + igt_info("Standard mode (%d) for connector %u is %ux%u\r\n", + i, + c->connector_id, + c->modes[i].hdisplay, + c->modes[i].vdisplay); + found_std = true; + } + /* Failsafe mode is 640x480@60 */ + if (c->modes[i].hdisplay == 640 && + c->modes[i].vdisplay == 480 && + c->modes[i].vrefresh == 60 && + found_fs == false) { + dp_conn->mode_failsafe = c->modes[i]; + dp_conn->failsafe_width = c->modes[i].hdisplay; + dp_conn->failsafe_height = c->modes[i].vdisplay; + igt_info("Failsafe mode (%d) for connector %u is %ux%u\r\n", + i, + c->connector_id, + c->modes[i].hdisplay, + c->modes[i].vdisplay); + found_fs = true; + } + } + + ret = setup_framebuffers(dp_conn); + if (ret) { + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", + c->connector_id, ret); + return ret; + } + + if (found_fs) { + ret = setup_failsafe_framebuffer(dp_conn); + if (ret) { + igt_warn("Creating failsafe framebuffer for connector %u failed (%d)\r\n", + c->connector_id, ret); + return ret; + } + } + + if (video_pattern_flag) { + dp_conn->test_pattern.hdisplay = hdisplay; + dp_conn->test_pattern.vdisplay = vdisplay; + dp_conn->test_pattern.bitdepth = bitdepth; + + ret = setup_video_pattern_framebuffer(dp_conn); + if (ret) { + igt_warn("Creating framebuffer for connector %u failed (%d)\r\n", + c->connector_id, ret); + return ret; + } + + ret = fill_framebuffer(dp_conn); + if (ret) { + igt_warn("Filling framebuffer for connector %u failed (%d)\r\n", + c->connector_id, ret); + return ret; + } + } + + return ret; +} + +static int set_video(int mode, struct connector *test_connector) +{ + drmModeModeInfo *requested_mode; + uint32_t required_fb_id; + struct igt_fb required_fb; + int ret = 0; + + switch (mode) { + case INTEL_MODE_NONE: + igt_info("NONE\r\n"); + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, + -1, 0, 0, NULL, 0, NULL); + goto out; + case INTEL_MODE_PREFERRED: + igt_info("PREFERRED\r\n"); + requested_mode = &test_connector->mode_preferred; + required_fb_id = test_connector->fb; + required_fb = test_connector->fb_video_pattern; + break; + case INTEL_MODE_STANDARD: + igt_info("STANDARD\r\n"); + requested_mode = &test_connector->mode_standard; + required_fb_id = test_connector->fb; + required_fb = test_connector->fb_video_pattern; + break; + case INTEL_MODE_FAILSAFE: + igt_info("FAILSAFE\r\n"); + requested_mode = &test_connector->mode_failsafe; + required_fb_id = test_connector->failsafe_fb; + required_fb = test_connector->fb_failsafe_pattern; + break; + case INTEL_MODE_VIDEO_PATTERN_TEST: + igt_info("VIDEO PATTERN TEST\r\n"); + requested_mode = &test_connector->test_pattern.mode; + required_fb_id = test_connector->test_pattern.fb; + required_fb = test_connector->test_pattern.fb_pattern; + break; + case INTEL_MODE_INVALID: + default: + igt_warn("INVALID! (%08x) Mode set aborted!\r\n", mode); + return -1; + } + + igt_info("CRTC(%u):", test_connector->crtc); + kmstest_dump_mode(requested_mode); + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0, + &test_connector->id, 1, requested_mode); + if (ret) { + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", + requested_mode->hdisplay, requested_mode->vdisplay, + requested_mode->vrefresh, strerror(errno)); + igt_remove_fb(drm_fd, &required_fb); + + } + /* Keep the pattern on output lines for 1 sec for DPR-120 to detect it */ + sleep(1); + +out: + if (ret) { + igt_warn("Failed to set CRTC for connector %u\r\n", + test_connector->id); + } + + return ret; +} + +static int +set_default_mode(struct connector *c, bool set_mode) +{ + unsigned int fb_id = 0; + struct igt_fb fb_info; + int ret = 0; + + if (!set_mode) { + ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0, + NULL, 0, NULL); + if (ret) + igt_warn("Failed to unset mode"); + return ret; + } + + c->mode = c->connector->modes[0]; + + width = c->mode.hdisplay; + height = c->mode.vdisplay; + + fb_id = igt_create_pattern_fb(drm_fd, width, height, + DRM_FORMAT_XRGB8888, + tiling, &fb_info); + + igt_info("CRTC(%u):[%d]", c->crtc, 0); + kmstest_dump_mode(&c->mode); + drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL); + ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, + &c->id, 1, &c->mode); + if (ret) { + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n", + width, height, c->mode.vrefresh, strerror(errno)); + igt_remove_fb(drm_fd, &fb_info); + + } + + return ret; +} + +static uint32_t find_crtc_for_connector(drmModeConnector *c) +{ + drmModeEncoder *e; + uint32_t possible_crtcs; + int i, j; + + for (i = 0; i < c->count_encoders; i++) { + e = drmModeGetEncoder(drm_fd, c->encoders[i]); + possible_crtcs = e->possible_crtcs; + drmModeFreeEncoder(e); + + for (j = 0; possible_crtcs >> j; j++) + if (possible_crtcs & (1 << j)) + return resources->crtcs[j]; + } + return 0; +} + +/* + * Re-probe connectors and do a modeset based on test request or + * in case of a hotplug uevent. + * + * @mode: Video mode requested by the test + * @is_compliance_test: 1: If it is a compliance test + * 0: If it is a hotplug event + * + * Returns: + * 0: On Success + * -1: On failure + */ +int update_display(int mode, bool is_compliance_test) +{ + struct connector *connectors, *conn; + int cnt, ret = 0; + bool set_mode; + + resources = drmModeGetResources(drm_fd); + if (!resources) { + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); + return -1; + } + + connectors = calloc(resources->count_connectors, + sizeof(struct connector)); + if (!connectors) + return -1; + + /* Find any connected displays */ + for (cnt = 0; cnt < resources->count_connectors; cnt++) { + drmModeConnector *c; + + conn = &connectors[cnt]; + conn->id = resources->connectors[cnt]; + c = drmModeGetConnector(drm_fd, conn->id); + if (c->connector_type == DRM_MODE_CONNECTOR_DisplayPort && + c->connection == DRM_MODE_CONNECTED) { + test_connector_id = c->connector_id; + conn->connector = c; + conn->crtc = find_crtc_for_connector(c); + test_crtc = conn->crtc; + set_mode = true; + break; + } else if (c->connector_id == test_connector_id && + c->connection == DRM_MODE_DISCONNECTED) { + conn->connector = c; + conn->crtc = test_crtc; + set_mode = false; + break; + } + } + + if (cnt == resources->count_connectors) { + ret = -1; + goto err; + } + + if (is_compliance_test) { + set_test_mode(conn); + ret = set_video(INTEL_MODE_NONE, conn); + ret = set_video(mode, conn); + + } else + ret = set_default_mode(conn, set_mode); + + err: + drmModeFreeConnector(conn->connector); + /* Error condition if no connected displays */ + free(connectors); + drmModeFreeResources(resources); + return ret; +} + +static const char optstr[] = "hi"; + +static void __attribute__((noreturn)) usage(char *name, char opt) +{ + igt_info("usage: %s [-hi]\n", name); + igt_info("\t-i\tdump info\n"); + igt_info("\tDefault is to respond to DPR-120 tests\n"); + exit((opt != 'h') ? -1 : 0); +} + +static void cleanup_debugfs(void) +{ + fclose(test_active_fp); + fclose(test_data_fp); + fclose(test_type_fp); +} + +static void __attribute__((noreturn)) cleanup_and_exit(int ret) +{ + cleanup_debugfs(); + close(drm_fd); + igt_info("Compliance testing application exiting\n"); + exit(ret); +} + +static void cleanup_test(void) +{ + video_pattern_flag = false; + hdisplay = 0; + vdisplay = 0; + bitdepth = 0; +} + +static void read_test_request(void) +{ + unsigned long test_type; + + test_type = get_test_type(); + process_test_request(test_type); + cleanup_test(); + clear_test_active(); +} + +static gboolean test_handler(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + unsigned long test_active; + int ret; + + rewind(test_active_fp); + + ret = fscanf(test_active_fp, "%lx", &test_active); + if (ret < 1) + return FALSE; + + if (test_active) + read_test_request(); + return TRUE; +} + +static gboolean input_event(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + gchar buf[2]; + gsize count; + + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf)); + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) { + cleanup_and_exit(0); + } + + return TRUE; +} + +static void enter_exec_path(char **argv) +{ + char *exec_path = NULL; + char *pos = NULL; + short len_path = 0; + int ret; + + len_path = strlen(argv[0]); + exec_path = (char *) malloc(len_path); + + memcpy(exec_path, argv[0], len_path); + pos = strrchr(exec_path, '/'); + if (pos != NULL) + *(pos+1) = '\0'; + + ret = chdir(exec_path); + igt_assert_eq(ret, 0); + free(exec_path); +} + +static void restore_termio_mode(int sig) +{ + tcsetattr(tio_fd, TCSANOW, &saved_tio); + close(tio_fd); +} + +static void set_termio_mode(void) +{ + struct termios tio; + + /* don't attempt to set terminal attributes if not in the foreground + * process group + */ + if (getpgrp() != tcgetpgrp(STDOUT_FILENO)) + return; + + tio_fd = dup(STDIN_FILENO); + tcgetattr(tio_fd, &saved_tio); + igt_install_exit_handler(restore_termio_mode); + tio = saved_tio; + tio.c_lflag &= ~(ICANON | ECHO); + tcsetattr(tio_fd, TCSANOW, &tio); +} + +int main(int argc, char **argv) +{ + int c; + int ret = 0; + GIOChannel *stdinchannel, *testactive_channel; + GMainLoop *mainloop; + bool opt_dump_info = false; + struct option long_opts[] = { + {"help-description", 0, 0, HELP_DESCRIPTION}, + {"help", 0, 0, 'h'}, + }; + + igt_skip_on_simulation(); + + enter_exec_path(argv); + + while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) { + switch (c) { + case 'i': + opt_dump_info = true; + break; + case HELP_DESCRIPTION: + igt_info("DP Compliance Test Suite using DPR-120\n"); + igt_info("EDID tests\n"); + igt_info("Video Pattern Generation tests\n"); + exit(0); + break; + default: + /* fall through */ + case 'h': + usage(argv[0], c); + break; + } + } + + set_termio_mode(); + + igt_info("*************DP Compliance Testing using DPR-120*************\n"); + igt_info("Waiting for test request......\n"); + drm_fd = drm_open_driver(DRIVER_ANY); + + kmstest_set_vt_graphics_mode(); + setup_debugfs_files(); + cleanup_test(); + + if (opt_dump_info) { + dump_info(); + goto out_close; + } + + /* Get the DP connector ID and CRTC */ + if (update_display(0, false)) { + igt_warn("Failed to set default mode\n"); + ret = -1; + goto out_close; + } + + mainloop = g_main_loop_new(NULL, FALSE); + if (!mainloop) { + igt_warn("Failed to create GMainLoop\n"); + ret = -1; + goto out_close; + } + + if (!intel_dp_compliance_setup_hotplug()) { + igt_warn("Failed to initialize hotplug support\n"); + goto out_mainloop; + } + + testactive_channel = g_io_channel_unix_new(fileno(test_active_fp)); + if (!testactive_channel) { + igt_warn("Failed to create test_active GIOChannel\n"); + goto out_close; + } + + ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR, + test_handler, NULL); + if (ret < 0) { + igt_warn("Failed to add watch on udev GIOChannel\n"); + goto out_close; + } + + stdinchannel = g_io_channel_unix_new(0); + if (!stdinchannel) { + igt_warn("Failed to create stdin GIOChannel\n"); + goto out_hotplug; + } + + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event, + NULL); + if (ret < 0) { + igt_warn("Failed to add watch on stdin GIOChannel\n"); + goto out_stdio; + } + + ret = 0; + + g_main_loop_run(mainloop); + +out_stdio: + g_io_channel_shutdown(stdinchannel, TRUE, NULL); +out_hotplug: + intel_dp_compliance_cleanup_hotplug(); +out_mainloop: + g_main_loop_unref(mainloop); +out_close: + cleanup_debugfs(); + close(drm_fd); + + igt_assert_eq(ret, 0); + + igt_info("Compliance testing application exiting\n"); + igt_exit(); +} diff --git a/tools/intel_dp_compliance.h b/tools/intel_dp_compliance.h new file mode 100644 index 0000000..ade1e2f --- /dev/null +++ b/tools/intel_dp_compliance.h @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Intel Corporation + * Manasi Navare <manasi.d.navare@intel.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <glib.h> + +extern int drm_fd; + +gboolean intel_dp_compliance_setup_hotplug(void); +void intel_dp_compliance_cleanup_hotplug(void); + +/* called by the hotplug code */ +int update_display(int mode, bool is_compliance_test); diff --git a/tools/intel_dp_compliance_hotplug.c b/tools/intel_dp_compliance_hotplug.c new file mode 100644 index 0000000..7c7ea65 --- /dev/null +++ b/tools/intel_dp_compliance_hotplug.c @@ -0,0 +1,123 @@ +/* + * Copyright 2010 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "igt.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> + +#include "intel_dp_compliance.h" +#include <libudev.h> +static struct udev_monitor *uevent_monitor; +static struct udev *udev; +static GIOChannel *udevchannel; + +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + struct udev_device *dev; + dev_t udev_devnum; + struct stat s; + const char *hotplug; + + dev = udev_monitor_receive_device(uevent_monitor); + if (!dev) + goto out; + + udev_devnum = udev_device_get_devnum(dev); + fstat(drm_fd, &s); + + hotplug = udev_device_get_property_value(dev, "HOTPLUG"); + + if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 && + hotplug && atoi(hotplug) == 1) + update_display(0, false); + + udev_device_unref(dev); +out: + return TRUE; +} + + +gboolean intel_dp_compliance_setup_hotplug(void) +{ + int ret; + + udev = udev_new(); + if (!udev) { + igt_warn("Failed to create udev object\n"); + goto out; + } + + uevent_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!uevent_monitor) { + igt_warn("Failed to create udev event monitor\n"); + goto out; + } + + ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor, + "drm", + "drm_minor"); + if (ret < 0) { + igt_warn("Failed to filter for drm events\n"); + goto out; + } + + ret = udev_monitor_enable_receiving(uevent_monitor); + if (ret < 0) { + igt_warn("Failed to enable udev event reception\n"); + goto out; + } + + udevchannel = + g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor)); + if (!udevchannel) { + igt_warn("Failed to create udev GIOChannel\n"); + goto out; + } + + ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event, + udev); + if (ret < 0) { + igt_warn("Failed to add watch on udev GIOChannel\n"); + goto out; + } + + return TRUE; + +out: + intel_dp_compliance_cleanup_hotplug(); + return FALSE; +} + +void intel_dp_compliance_cleanup_hotplug(void) +{ + if (udevchannel) + g_io_channel_shutdown(udevchannel, TRUE, NULL); + if (uevent_monitor) + udev_monitor_unref(uevent_monitor); + if (udev) + udev_unref(udev); +}