[igt-dev] [PATCH i-g-t 5/5] tools: add support for msm_dp_compliance to IGT
abhinavk at codeaurora.org
abhinavk at codeaurora.org
Tue Sep 15 16:33:27 UTC 2020
Hi,
On 2020-09-15 00:46, Petri Latvala wrote:
> On Thu, Sep 03, 2020 at 05:54:39PM -0700, Abhinav Kumar wrote:
>> Add support for msm_dp_compliance to igt tools to validate
>> video pattern DP compliance tests on MSM chipsets.
>>
>> Signed-off-by: Abhinav Kumar <abhinavk at codeaurora.org>
>> ---
>> tools/Makefile.am | 4 +
>> tools/Makefile.sources | 6 +
>> tools/meson.build | 12 +
>> tools/msm_dp_compliance.c | 812
>> ++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 834 insertions(+)
>> create mode 100644 tools/msm_dp_compliance.c
>>
>> diff --git a/tools/Makefile.am b/tools/Makefile.am
>> index f97f9e08..eac52be8 100644
>> --- a/tools/Makefile.am
>> +++ b/tools/Makefile.am
>> @@ -14,6 +14,10 @@ intel_dp_compliance_LDADD =
>> $(top_builddir)/lib/libintel_tools.la
>> bin_PROGRAMS += amd_hdmi_compliance
>> amd_hdmi_compliance_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
>>
>> +bin_PROGRAMS += msm_dp_compliance
>> +msm_dp_compliance_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
>> +msm_dp_compliance_LDADD = $(top_builddir)/lib/libintel_tools.la
>> +
>> SUBDIRS = i915-perf null_state_gen registers
>>
>> AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include/drm-uapi
>> -I$(top_srcdir)/lib \
>> diff --git a/tools/Makefile.sources b/tools/Makefile.sources
>> index 47171490..c93bfe7d 100644
>> --- a/tools/Makefile.sources
>> +++ b/tools/Makefile.sources
>> @@ -72,3 +72,9 @@ amd_hdmi_compliance_SOURCES = \
>> amd_hdmi_compliance.c \
>> $(NULL)
>>
>> +msm_dp_compliance_SOURCES = \
>> + msm_dp_compliance.c \
>> + igt_dp_compliance.h \
>> + igt_dp_compliance_hotplug.c \
>> + igt_compliance_utils.c \
>> + $(NULL)
>> diff --git a/tools/meson.build b/tools/meson.build
>> index 56877fb3..65f78938 100644
>> --- a/tools/meson.build
>> +++ b/tools/meson.build
>> @@ -101,5 +101,17 @@ executable('amd_hdmi_compliance',
>> 'amd_hdmi_compliance.c',
>> install_rpath : bindir_rpathdir,
>> install : true)
>>
>> +if libudev.found()
>> + msm_dp_compliance_src = [
>> + 'msm_dp_compliance.c',
>> + 'igt_dp_compliance_hotplug.c',
>> + 'igt_compliance_utils.c'
>> + ]
>
> Check indentation here for the msm_dp_compliance_src = [ line.
>
> Otherwise looks good,
> Acked-by: Petri Latvala <petri.latvala at intel.com>
>
> For future changes that affect this tool, do you want to be the main
> contact person to ask for acks/tests/opinions?
>
>
> --
> Petri Latvala
Thanks so much for the review. Will check the indent.
Yes, I will be the main contact person to ask for acks/tests/opinions on
this tool.
>
>
>
>> + executable('msm_dp_compliance', sources : msm_dp_compliance_src,
>> + dependencies : [tool_deps, libudev],
>> + install_rpath : bindir_rpathdir,
>> + install : true)
>> +endif
>> +
>> subdir('i915-perf')
>> subdir('null_state_gen')
>> diff --git a/tools/msm_dp_compliance.c b/tools/msm_dp_compliance.c
>> new file mode 100644
>> index 00000000..7bc2bfa8
>> --- /dev/null
>> +++ b/tools/msm_dp_compliance.c
>> @@ -0,0 +1,812 @@
>> +/*
>> + * Copyright (c) 2020, The Linux Foundation. All rights reserved.
>> + * Copyright © 2017 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 MSM 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 Qdbox 980
>> + * - This user application
>> + * - A windows host machine to run the Qdbox 980 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:
>> + * - 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:
>> + *
>> + * msm_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.
>> + *
>> + * msm_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.
>> + *
>> + * msm_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 at gmail.com>).
>> + *
>> + * This work is based upon the intel_dp_compliance.c authored by
>> + * Manasi Navare <manasi.d.navare at intel.com>
>> + *
>> + *
>> + * This tool can be run as:
>> + * ./msm_dp_compliance It will wait till you start compliance suite
>> from
>> + * Qdbox 980.
>> + * ./msm_dp_compliance -h This will open the help
>> + * ./msm_dp_compliance -i This will provide information about
>> current
>> + * connectors/CRTCs. This can be used for debugging purpose.
>> + *
>> + * Authors:
>> + * Abhinav Kumar <abhinavk at codeaurora.org>
>> + *
>> + * 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 "igt_dp_compliance.h"
>> +
>> +#include <stdlib.h>
>> +#include <signal.h>
>> +
>> +/* User Input definitions */
>> +#define HELP_DESCRIPTION 1
>> +
>> +/* Debugfs file definitions */
>> +#define MSM_DP_TEST_TYPE_FILE "msm_dp_test_type"
>> +#define MSM_DP_TEST_ACTIVE_FILE "msm_dp_test_active"
>> +#define MSM_DP_TEST_DATA_FILE "msm_dp_test_data"
>> +
>> +/* DRM definitions - must be kept in sync with the DRM header */
>> +#define DP_TEST_LINK_VIDEO_PATTERN (1 << 1)
>> +
>> +/* 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;
>> +
>> +drmModeRes *resources;
>> +int drm_fd, modes, gen;
>> +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 active_crtc;
>> +uint32_t test_connector_id;
>> +enum {
>> + MSM_MODE_INVALID = -1,
>> + MSM_MODE_NONE = 0,
>> + MSM_MODE_VIDEO_PATTERN_TEST
>> +} msm_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_failsafe;
>> + drmModeConnector *connector;
>> + int crtc;
>> + /* Standard and preferred frame buffer*/
>> + uint8_t *pixmap;
>> +
>> + 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 FILE *fopenat(int dir, const char *name, const char *mode)
>> +{
>> + int fd = openat(dir, name, O_RDWR);
>> +
>> + return fdopen(fd, mode);
>> +}
>> +
>> +static void setup_debugfs_files(void)
>> +{
>> + int dir = igt_debugfs_dir(drm_fd);
>> +
>> + test_type_fp = fopenat(dir, MSM_DP_TEST_TYPE_FILE, "r");
>> + igt_require(test_type_fp);
>> +
>> + test_data_fp = fopenat(dir, MSM_DP_TEST_DATA_FILE, "r");
>> + igt_require(test_data_fp);
>> + test_active_fp = fopenat(dir, MSM_DP_TEST_ACTIVE_FILE, "w+");
>> +
>> + igt_require(test_active_fp);
>> +
>> + close(dir);
>> +
>> + /* 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\n");
>> + rewind(test_type_fp);
>> + ret = fscanf(test_type_fp, "%lx", &test_type);
>> + if (ret < 1 || test_type <= 0) {
>> + igt_warn("test_type read failed - %lx\n", test_type);
>> + return 0;
>> + }
>> +
>> + return test_type;
>> +}
>> +
>> +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\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\n", hdisplay);
>> + igt_info("Vdisplay = %d\n", vdisplay);
>> + igt_info("BitDepth = %u\n", bitdepth);
>> +
>> +}
>> +
>> +static int process_test_request(int test_type)
>> +{
>> + int mode;
>> + bool valid = false;
>> +
>> + switch (test_type) {
>> + case DP_TEST_LINK_VIDEO_PATTERN:
>> + video_pattern_flag = true;
>> + get_test_videopattern_data();
>> + mode = MSM_MODE_VIDEO_PATTERN_TEST;
>> + valid = true;
>> + break;
>> + default:
>> + /* Unknown test type */
>> + fprintf(stderr, "Invalid test request, ignored.\n");
>> + break;
>> + }
>> +
>> + if (valid)
>> + return update_display(mode, true);
>> +
>> + return -1;
>> +}
>> +
>> +static void dump_info(void)
>> +{
>> + igt_dump_connectors_fd(drm_fd);
>> + igt_dump_crtcs_fd(drm_fd);
>> +}
>> +
>> +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);
>> +
>> +
>> + dp_conn->test_pattern.pixmap = kmstest_dumb_map_buffer(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;
>> +
>> + 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 set_test_mode(struct connector *dp_conn)
>> +{
>> + int ret = 0;
>> + int i;
>> + drmModeConnector *c = dp_conn->connector;
>> +
>> + /* Ignore any disconnected devices */
>> + if (c->connection != DRM_MODE_CONNECTED) {
>> + igt_warn("Connector %u disconnected\n", c->connector_id);
>> + return -ENOENT;
>> + }
>> + igt_info("Connector setup:\n");
>> +
>> + /*
>> + * to-do: for cases where driver doesn't support 4K but
>> + * its the preferred mode of the sink, use 640x480 as
>> + * default resolution
>> + */
>> +
>> + for (i = 0; i < c->count_modes; i++) {
>> + if (c->modes[i].hdisplay == 640 &&
>> + c->modes[i].vdisplay == 480 &&
>> + c->modes[i].vrefresh == 60) {
>> + igt_info("found idx of failsafe mode = %d\n", i);
>> + break;
>> + }
>> + }
>> +
>> + if (i == c->count_modes) {
>> + igt_info("didn't find failsafe using default\n");
>> + i = 0;
>> + }
>> +
>> + dp_conn->test_pattern.mode = c->modes[i];
>> + dp_conn->test_pattern.mode.hdisplay = c->modes[i].hdisplay;
>> + dp_conn->test_pattern.mode.vdisplay = c->modes[i].vdisplay;
>> +
>> + igt_info("failsafe (mode %d) for connector %u is %ux%u\n", i,
>> + dp_conn->id, c->modes[i].hdisplay, c->modes[i].vdisplay);
>> + fflush(stdin);
>> +
>> + 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)\n",
>> + c->connector_id, ret);
>> + return ret;
>> + }
>> +
>> + ret = igt_fill_cts_framebuffer(dp_conn->test_pattern.pixmap,
>> + dp_conn->test_pattern.hdisplay,
>> + dp_conn->test_pattern.vdisplay,
>> + dp_conn->test_pattern.bitdepth,
>> + 0);
>> + if (ret) {
>> + igt_warn("Filling framebuffer for connector %u failed (%d)\n",
>> + c->connector_id, ret);
>> + return ret;
>> + }
>> + /* unmapping the buffer previously mapped during setup */
>> + munmap(dp_conn->test_pattern.pixmap,
>> + dp_conn->test_pattern.size);
>> + }
>> +
>> + 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 MSM_MODE_NONE:
>> + igt_info("NONE\n");
>> + ret = drmModeSetCrtc(drm_fd, test_connector->crtc,
>> + -1, 0, 0, NULL, 0, NULL);
>> + goto out;
>> + case MSM_MODE_VIDEO_PATTERN_TEST:
>> + igt_info("VIDEO PATTERN TEST\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 MSM_MODE_INVALID:
>> + default:
>> + igt_warn("INVALID! (%08x) Mode set aborted!\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 for 1 sec for Qdbox 980 to detect it */
>> + sleep(1);
>> +
>> +out:
>> + if (ret) {
>> + igt_warn("Failed to set CRTC for connector %u\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;
>> + int i;
>> + drmModeConnector *conn = c->connector;
>> +
>> + if (!set_mode) {
>> + igt_info("not resetting the mode\n");
>> + ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0,
>> + NULL, 0, NULL);
>> + if (ret)
>> + igt_warn("Failed to unset mode");
>> + return ret;
>> + }
>> +
>> + for (i = 0; i < conn->count_modes; i++) {
>> + if (conn->modes[i].hdisplay == 640 &&
>> + conn->modes[i].vdisplay == 480 &&
>> + conn->modes[i].vrefresh == 60) {
>> + igt_info("found idx of failsafe mode = %d\n", i);
>> + break;
>> + }
>> + }
>> +
>> + if (i == conn->count_modes) {
>> + igt_info("didn't find failsafe using default\n");
>> + i = 0;
>> + }
>> +
>> + c->mode = c->connector->modes[i];
>> +
>> + width = c->mode.hdisplay;
>> + height = c->mode.vdisplay;
>> +
>> + fb_id = igt_create_pattern_fb(drm_fd, width, height,
>> + DRM_FORMAT_XRGB8888,
>> + tiling, &fb_info);
>> +
>> + 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;
>> + drmModeCrtcPtr crtc_ptr;
>> + int i;
>> +
>> + active_crtc = 0;
>> +
>> + for (i = 0; i < c->count_encoders; i++) {
>> + e = drmModeGetEncoder(drm_fd, c->encoders[i]);
>> +
>> + /* if there is an active crtc use it */
>> + if (e->crtc_id) {
>> + active_crtc = e->crtc_id;
>> + drmModeFreeEncoder(e);
>> + break;
>> + }
>> + drmModeFreeEncoder(e);
>> + }
>> +
>> + /* no need to search further if active crtc is found */
>> + if (active_crtc)
>> + return active_crtc;
>> +
>> + /*
>> + * if there is no active crtc find one from the list of
>> + * unused ones. Cannot use anything from possible_crtc of
>> + * of encoder because it then tries to steal the crtc of the
>> + * primary display. DPU driver does not support switching CRTCs
>> + * across displays in the same commit. Hence need to find some
>> + * other unused crtc.
>> + */
>> + for (i = 0; i < resources->count_crtcs; i++) {
>> + crtc_ptr = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
>> + /* if a crtc which is unused is found , use it */
>> + if (!crtc_ptr->mode_valid) {
>> + active_crtc = crtc_ptr->crtc_id;
>> + drmModeFreeCrtc(crtc_ptr);
>> + break;
>> + }
>> + drmModeFreeCrtc(crtc_ptr);
>> + }
>> +
>> + return active_crtc;
>> +}
>> +
>> +/*
>> + * 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;
>> + //int crtc;
>> +
>> + 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(MSM_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 Qd980 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;
>> +}
>> +
>> +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'},
>> + };
>> +
>> + 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 Qd 980\n");
>> + igt_info("Video Pattern Generation tests\n");
>> + exit(0);
>> + break;
>> + default:
>> + /* fall through */
>> + case 'h':
>> + usage(argv[0], c);
>> + break;
>> + }
>> + }
>> +
>> + set_termio_mode();
>> +
>> + 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 (!igt_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;
>> +
>> + igt_info("*************DP Compliance Testing using Qdbox
>> 980*************\n");
>> + igt_info("Waiting for test request......\n");
>> +
>> + g_main_loop_run(mainloop);
>> +
>> +out_stdio:
>> + g_io_channel_shutdown(stdinchannel, TRUE, NULL);
>> +out_hotplug:
>> + igt_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();
>> +}
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
>> Forum,
>> a Linux Foundation Collaborative Project
>>
>> _______________________________________________
>> igt-dev mailing list
>> igt-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/igt-dev
More information about the igt-dev
mailing list