From 8809638e8e42488aac701066d7ced164854c6c9c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 16 Nov 2017 13:33:14 +0100 Subject: tests: Rename chamelium to kms_chamelium. Signed-off-by: Maarten Lankhorst Reviewed-by: Lyude Paul Acked-by: Martin Peres --- tests/kms_chamelium.c | 936 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 936 insertions(+) create mode 100644 tests/kms_chamelium.c (limited to 'tests/kms_chamelium.c') diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c new file mode 100644 index 00000000..8855a830 --- /dev/null +++ b/tests/kms_chamelium.c @@ -0,0 +1,936 @@ +/* + * Copyright © 2016 Red Hat Inc. + * + * 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. + * + * Authors: + * Lyude Paul + */ + +#include "config.h" +#include "igt.h" + +#include +#include + +typedef struct { + struct chamelium *chamelium; + struct chamelium_port **ports; + igt_display_t display; + int port_count; + + int drm_fd; + + int edid_id; + int alt_edid_id; +} data_t; + +#define HOTPLUG_TIMEOUT 20 /* seconds */ + +#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */ +#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */ + +#define HPD_TOGGLE_COUNT_VGA 5 +#define HPD_TOGGLE_COUNT_DP_HDMI 15 +#define HPD_TOGGLE_COUNT_FAST 3 + +static void +get_connectors_link_status_failed(data_t *data, bool *link_status_failed) +{ + drmModeConnector *connector; + uint64_t link_status; + drmModePropertyPtr prop; + int p; + + for (p = 0; p < data->port_count; p++) { + connector = chamelium_port_get_connector(data->chamelium, + data->ports[p], false); + + igt_assert(kmstest_get_property(data->drm_fd, + connector->connector_id, + DRM_MODE_OBJECT_CONNECTOR, + "link-status", NULL, + &link_status, &prop)); + + link_status_failed[p] = link_status == DRM_MODE_LINK_STATUS_BAD; + + drmModeFreeProperty(prop); + drmModeFreeConnector(connector); + } +} + +static void +require_connector_present(data_t *data, unsigned int type) +{ + int i; + bool found = false; + + for (i = 0; i < data->port_count && !found; i++) { + if (chamelium_port_get_type(data->ports[i]) == type) + found = true; + } + + igt_require_f(found, "No port of type %s was found\n", + kmstest_connector_type_str(type)); +} + +static drmModeConnection +reprobe_connector(data_t *data, struct chamelium_port *port) +{ + drmModeConnector *connector; + drmModeConnection status; + + igt_debug("Reprobing %s...\n", chamelium_port_get_name(port)); + connector = chamelium_port_get_connector(data->chamelium, port, true); + igt_assert(connector); + status = connector->connection; + + drmModeFreeConnector(connector); + return status; +} + +static void +wait_for_connector(data_t *data, struct chamelium_port *port, + drmModeConnection status) +{ + bool finished = false; + + igt_debug("Waiting for %s to %sconnect...\n", + chamelium_port_get_name(port), + status == DRM_MODE_DISCONNECTED ? "dis" : ""); + + /* + * Rely on simple reprobing so we don't fail tests that don't require + * that hpd events work in the event that hpd doesn't work on the system + */ + igt_until_timeout(HOTPLUG_TIMEOUT) { + if (reprobe_connector(data, port) == status) { + finished = true; + return; + } + + usleep(50000); + } + + igt_assert(finished); +} + +static int chamelium_vga_modes[][2] = { + { 1600, 1200 }, + { 1920, 1200 }, + { 1920, 1080 }, + { 1680, 1050 }, + { 1280, 1024 }, + { 1280, 960 }, + { 1440, 900 }, + { 1280, 800 }, + { 1024, 768 }, + { 1360, 768 }, + { 1280, 720 }, + { 800, 600 }, + { 640, 480 }, + { -1, -1 }, +}; + +static bool +prune_vga_mode(data_t *data, drmModeModeInfo *mode) +{ + int i = 0; + + while (chamelium_vga_modes[i][0] != -1) { + if (mode->hdisplay == chamelium_vga_modes[i][0] && + mode->vdisplay == chamelium_vga_modes[i][1]) + return false; + + i++; + } + + return true; +} + +static bool +check_analog_bridge(data_t *data, struct chamelium_port *port) +{ + drmModePropertyBlobPtr edid_blob = NULL; + drmModeConnector *connector = chamelium_port_get_connector( + data->chamelium, port, false); + uint64_t edid_blob_id; + unsigned char *edid; + char edid_vendor[3]; + + if (chamelium_port_get_type(port) != DRM_MODE_CONNECTOR_VGA) + return false; + + igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id, + DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL, + &edid_blob_id, NULL)); + igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd, + edid_blob_id)); + + edid = (unsigned char *) edid_blob->data; + + edid_vendor[0] = ((edid[8] & 0x7c) >> 2) + '@'; + edid_vendor[1] = (((edid[8] & 0x03) << 3) | + ((edid[9] & 0xe0) >> 5)) + '@'; + edid_vendor[2] = (edid[9] & 0x1f) + '@'; + + /* Analog bridges provide their own EDID */ + if (edid_vendor[0] != 'I' || edid_vendor[1] != 'G' || + edid_vendor[0] != 'T') + return true; + + drmModeFreePropertyBlob(edid_blob); + drmModeFreeConnector(connector); + + return false; +} + +static void +reset_state(data_t *data, struct chamelium_port *port) +{ + int p; + + chamelium_reset(data->chamelium); + + if (port) { + wait_for_connector(data, port, DRM_MODE_DISCONNECTED); + } else { + for (p = 0; p < data->port_count; p++) { + port = data->ports[p]; + wait_for_connector(data, port, DRM_MODE_DISCONNECTED); + } + } +} + +static void +test_basic_hotplug(data_t *data, struct chamelium_port *port, int toggle_count) +{ + struct udev_monitor *mon = igt_watch_hotplug(); + int i; + + reset_state(data, NULL); + igt_hpd_storm_set_threshold(data->drm_fd, 0); + + for (i = 0; i < toggle_count; i++) { + igt_flush_hotplugs(mon); + + /* Check if we get a sysfs hotplug event */ + chamelium_plug(data->chamelium, port); + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + igt_assert_eq(reprobe_connector(data, port), + DRM_MODE_CONNECTED); + + igt_flush_hotplugs(mon); + + /* Now check if we get a hotplug from disconnection */ + chamelium_unplug(data->chamelium, port); + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + igt_assert_eq(reprobe_connector(data, port), + DRM_MODE_DISCONNECTED); + } + + igt_cleanup_hotplug(mon); + igt_hpd_storm_reset(data->drm_fd); +} + +static void +test_edid_read(data_t *data, struct chamelium_port *port, + int edid_id, const unsigned char *edid) +{ + drmModePropertyBlobPtr edid_blob = NULL; + drmModeConnector *connector = chamelium_port_get_connector( + data->chamelium, port, false); + uint64_t edid_blob_id; + + reset_state(data, port); + + chamelium_port_set_edid(data->chamelium, port, edid_id); + chamelium_plug(data->chamelium, port); + wait_for_connector(data, port, DRM_MODE_CONNECTED); + + igt_skip_on(check_analog_bridge(data, port)); + + igt_assert(kmstest_get_property(data->drm_fd, connector->connector_id, + DRM_MODE_OBJECT_CONNECTOR, "EDID", NULL, + &edid_blob_id, NULL)); + igt_assert(edid_blob = drmModeGetPropertyBlob(data->drm_fd, + edid_blob_id)); + + igt_assert(memcmp(edid, edid_blob->data, EDID_LENGTH) == 0); + + drmModeFreePropertyBlob(edid_blob); + drmModeFreeConnector(connector); +} + +static void +try_suspend_resume_hpd(data_t *data, struct chamelium_port *port, + enum igt_suspend_state state, enum igt_suspend_test test, + struct udev_monitor *mon, bool connected) +{ + int delay; + int p; + + igt_flush_hotplugs(mon); + + delay = igt_get_autoresume_delay(state) * 1000 / 2; + + if (port) { + chamelium_schedule_hpd_toggle(data->chamelium, port, delay, + !connected); + } else { + for (p = 0; p < data->port_count; p++) { + port = data->ports[p]; + chamelium_schedule_hpd_toggle(data->chamelium, port, + delay, !connected); + } + + port = NULL; + } + + igt_system_suspend_autoresume(state, test); + + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + if (port) { + igt_assert_eq(reprobe_connector(data, port), connected ? + DRM_MODE_DISCONNECTED : DRM_MODE_CONNECTED); + } else { + for (p = 0; p < data->port_count; p++) { + port = data->ports[p]; + igt_assert_eq(reprobe_connector(data, port), connected ? + DRM_MODE_DISCONNECTED : + DRM_MODE_CONNECTED); + } + + port = NULL; + } +} + +static void +test_suspend_resume_hpd(data_t *data, struct chamelium_port *port, + enum igt_suspend_state state, + enum igt_suspend_test test) +{ + struct udev_monitor *mon = igt_watch_hotplug(); + + reset_state(data, port); + + /* Make sure we notice new connectors after resuming */ + try_suspend_resume_hpd(data, port, state, test, mon, false); + + /* Now make sure we notice disconnected connectors after resuming */ + try_suspend_resume_hpd(data, port, state, test, mon, true); + + igt_cleanup_hotplug(mon); +} + +static void +test_suspend_resume_hpd_common(data_t *data, enum igt_suspend_state state, + enum igt_suspend_test test) +{ + struct udev_monitor *mon = igt_watch_hotplug(); + struct chamelium_port *port; + int p; + + for (p = 0; p < data->port_count; p++) { + port = data->ports[p]; + igt_debug("Testing port %s\n", chamelium_port_get_name(port)); + } + + reset_state(data, NULL); + + /* Make sure we notice new connectors after resuming */ + try_suspend_resume_hpd(data, NULL, state, test, mon, false); + + /* Now make sure we notice disconnected connectors after resuming */ + try_suspend_resume_hpd(data, NULL, state, test, mon, true); + + igt_cleanup_hotplug(mon); +} + +static void +test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port, + enum igt_suspend_state state, + enum igt_suspend_test test, + int edid_id, + int alt_edid_id) +{ + struct udev_monitor *mon = igt_watch_hotplug(); + bool link_status_failed[2][data->port_count]; + int p; + + reset_state(data, port); + + /* Catch the event and flush all remaining ones. */ + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + igt_flush_hotplugs(mon); + + /* First plug in the port */ + chamelium_port_set_edid(data->chamelium, port, edid_id); + chamelium_plug(data->chamelium, port); + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + + wait_for_connector(data, port, DRM_MODE_CONNECTED); + + /* + * Change the edid before we suspend. On resume, the machine should + * notice the EDID change and fire a hotplug event. + */ + chamelium_port_set_edid(data->chamelium, port, alt_edid_id); + + get_connectors_link_status_failed(data, link_status_failed[0]); + + igt_flush_hotplugs(mon); + + igt_system_suspend_autoresume(state, test); + + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + + get_connectors_link_status_failed(data, link_status_failed[1]); + + for (p = 0; p < data->port_count; p++) + igt_skip_on(!link_status_failed[0][p] && link_status_failed[1][p]); +} + +static igt_output_t * +prepare_output(data_t *data, + struct chamelium_port *port) +{ + igt_display_t *display = &data->display; + igt_output_t *output; + drmModeRes *res; + drmModeConnector *connector = + chamelium_port_get_connector(data->chamelium, port, false); + enum pipe pipe; + bool found = false; + + igt_assert(res = drmModeGetResources(data->drm_fd)); + + /* The chamelium's default EDID has a lot of resolutions, way more then + * we need to test + */ + chamelium_port_set_edid(data->chamelium, port, data->edid_id); + + chamelium_plug(data->chamelium, port); + wait_for_connector(data, port, DRM_MODE_CONNECTED); + + igt_display_reset(display); + + output = igt_output_from_connector(display, connector); + + for_each_pipe(display, pipe) { + if (!igt_pipe_connector_valid(pipe, output)) + continue; + + found = true; + break; + } + + igt_assert_f(found, "No pipe found for output %s\n", igt_output_name(output)); + + igt_output_set_pipe(output, pipe); + + drmModeFreeConnector(connector); + drmModeFreeResources(res); + + return output; +} + +static void +enable_output(data_t *data, + struct chamelium_port *port, + igt_output_t *output, + drmModeModeInfo *mode, + struct igt_fb *fb) +{ + igt_display_t *display = output->display; + igt_plane_t *primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + drmModeConnector *connector = chamelium_port_get_connector( + data->chamelium, port, false); + + igt_assert(primary); + + igt_plane_set_size(primary, mode->hdisplay, mode->vdisplay); + igt_plane_set_fb(primary, fb); + igt_output_override_mode(output, mode); + + /* Clear any color correction values that might be enabled */ + igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_DEGAMMA_LUT, NULL, 0); + igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_GAMMA_LUT, NULL, 0); + igt_pipe_obj_replace_prop_blob(primary->pipe, IGT_CRTC_CTM, NULL, 0); + + igt_display_commit2(display, COMMIT_ATOMIC); + + if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA) + usleep(250000); + + drmModeFreeConnector(connector); +} + +static void +test_display_crc(data_t *data, struct chamelium_port *port, int count, + bool fast) +{ + igt_output_t *output; + igt_plane_t *primary; + igt_crc_t *crc; + igt_crc_t *expected_crc; + struct chamelium_fb_crc_async_data *fb_crc; + struct igt_fb fb; + drmModeModeInfo *mode; + drmModeConnector *connector; + int fb_id, i, j, captured_frame_count; + int count_modes; + + reset_state(data, port); + + output = prepare_output(data, port); + connector = chamelium_port_get_connector(data->chamelium, port, false); + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_assert(primary); + + count_modes = fast ? 1 : connector->count_modes; + + for (i = 0; i < count_modes; i++) { + mode = &connector->modes[i]; + fb_id = igt_create_color_pattern_fb(data->drm_fd, + mode->hdisplay, + mode->vdisplay, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + 0, 0, 0, &fb); + igt_assert(fb_id > 0); + + fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd, + &fb); + + enable_output(data, port, output, mode, &fb); + + /* We want to keep the display running for a little bit, since + * there's always the potential the driver isn't able to keep + * the display running properly for very long + */ + chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count); + crc = chamelium_read_captured_crcs(data->chamelium, + &captured_frame_count); + + igt_assert(captured_frame_count == count); + + igt_debug("Captured %d frames\n", captured_frame_count); + + expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc); + + for (j = 0; j < captured_frame_count; j++) + chamelium_assert_crc_eq_or_dump(data->chamelium, + expected_crc, &crc[j], + &fb, j); + + free(expected_crc); + free(crc); + + igt_remove_fb(data->drm_fd, &fb); + } + + drmModeFreeConnector(connector); +} + +static void +test_display_frame_dump(data_t *data, struct chamelium_port *port) +{ + igt_output_t *output; + igt_plane_t *primary; + struct igt_fb fb; + struct chamelium_frame_dump *frame; + drmModeModeInfo *mode; + drmModeConnector *connector; + int fb_id, i, j; + + reset_state(data, port); + + output = prepare_output(data, port); + connector = chamelium_port_get_connector(data->chamelium, port, false); + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_assert(primary); + + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + fb_id = igt_create_color_pattern_fb(data->drm_fd, + mode->hdisplay, mode->vdisplay, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + 0, 0, 0, &fb); + igt_assert(fb_id > 0); + + enable_output(data, port, output, mode, &fb); + + igt_debug("Reading frame dumps from Chamelium...\n"); + chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5); + for (j = 0; j < 5; j++) { + frame = chamelium_read_captured_frame( + data->chamelium, j); + chamelium_assert_frame_eq(data->chamelium, frame, &fb); + chamelium_destroy_frame_dump(frame); + } + + igt_remove_fb(data->drm_fd, &fb); + } + + drmModeFreeConnector(connector); +} + +static void +test_analog_frame_dump(data_t *data, struct chamelium_port *port) +{ + igt_output_t *output; + igt_plane_t *primary; + struct igt_fb fb; + struct chamelium_frame_dump *frame; + drmModeModeInfo *mode; + drmModeConnector *connector; + int fb_id, i; + bool bridge; + + reset_state(data, port); + + output = prepare_output(data, port); + connector = chamelium_port_get_connector(data->chamelium, port, false); + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_assert(primary); + + bridge = check_analog_bridge(data, port); + + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + + if (bridge && prune_vga_mode(data, mode)) + continue; + + fb_id = igt_create_color_pattern_fb(data->drm_fd, + mode->hdisplay, mode->vdisplay, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + 0, 0, 0, &fb); + igt_assert(fb_id > 0); + + enable_output(data, port, output, mode, &fb); + + igt_debug("Reading frame dumps from Chamelium...\n"); + + frame = chamelium_port_dump_pixels(data->chamelium, port, 0, 0, + 0, 0); + + chamelium_crop_analog_frame(frame, mode->hdisplay, + mode->vdisplay); + + chamelium_assert_analog_frame_match_or_dump(data->chamelium, + port, frame, &fb); + + chamelium_destroy_frame_dump(frame); + + igt_remove_fb(data->drm_fd, &fb); + } + + drmModeFreeConnector(connector); +} + +static void +test_hpd_without_ddc(data_t *data, struct chamelium_port *port) +{ + struct udev_monitor *mon = igt_watch_hotplug(); + + reset_state(data, port); + igt_flush_hotplugs(mon); + + /* Disable the DDC on the connector and make sure we still get a + * hotplug + */ + chamelium_port_set_ddc_state(data->chamelium, port, false); + chamelium_plug(data->chamelium, port); + + igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT)); + igt_assert_eq(reprobe_connector(data, port), DRM_MODE_CONNECTED); + + igt_cleanup_hotplug(mon); +} + +static void +test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width) +{ + struct udev_monitor *mon; + int count = 0; + + igt_require_hpd_storm_ctl(data->drm_fd); + reset_state(data, port); + + igt_hpd_storm_set_threshold(data->drm_fd, 1); + chamelium_fire_hpd_pulses(data->chamelium, port, width, 10); + igt_assert(igt_hpd_storm_detected(data->drm_fd)); + + mon = igt_watch_hotplug(); + chamelium_fire_hpd_pulses(data->chamelium, port, width, 10); + + /* + * Polling should have been enabled by the HPD storm at this point, + * so we should only get at most 1 hotplug event + */ + igt_until_timeout(5) + count += igt_hotplug_detected(mon, 1); + igt_assert_lt(count, 2); + + igt_cleanup_hotplug(mon); + igt_hpd_storm_reset(data->drm_fd); +} + +static void +test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width) +{ + igt_require_hpd_storm_ctl(data->drm_fd); + reset_state(data, port); + + igt_hpd_storm_set_threshold(data->drm_fd, 0); + chamelium_fire_hpd_pulses(data->chamelium, port, + width, 10); + igt_assert(!igt_hpd_storm_detected(data->drm_fd)); + + igt_hpd_storm_reset(data->drm_fd); +} + +#define for_each_port(p, port) \ + for (p = 0, port = data.ports[p]; \ + p < data.port_count; \ + p++, port = data.ports[p]) + +#define connector_subtest(name__, type__) \ + igt_subtest(name__) \ + for_each_port(p, port) \ + if (chamelium_port_get_type(port) == \ + DRM_MODE_CONNECTOR_ ## type__) + +static data_t data; + +igt_main +{ + struct chamelium_port *port; + int edid_id, alt_edid_id, p; + + igt_fixture { + igt_skip_on_simulation(); + + data.drm_fd = drm_open_driver_master(DRIVER_ANY); + data.chamelium = chamelium_init(data.drm_fd); + igt_require(data.chamelium); + + data.ports = chamelium_get_ports(data.chamelium, + &data.port_count); + + edid_id = chamelium_new_edid(data.chamelium, + igt_kms_get_base_edid()); + alt_edid_id = chamelium_new_edid(data.chamelium, + igt_kms_get_alt_edid()); + data.edid_id = edid_id; + data.alt_edid_id = alt_edid_id; + + /* So fbcon doesn't try to reprobe things itself */ + kmstest_set_vt_graphics_mode(); + + igt_display_init(&data.display, data.drm_fd); + igt_require(data.display.is_atomic); + } + + igt_subtest_group { + igt_fixture { + require_connector_present( + &data, DRM_MODE_CONNECTOR_DisplayPort); + } + + connector_subtest("dp-hpd", DisplayPort) + test_basic_hotplug(&data, port, + HPD_TOGGLE_COUNT_DP_HDMI); + + connector_subtest("dp-hpd-fast", DisplayPort) + test_basic_hotplug(&data, port, + HPD_TOGGLE_COUNT_FAST); + + connector_subtest("dp-edid-read", DisplayPort) { + test_edid_read(&data, port, edid_id, + igt_kms_get_base_edid()); + test_edid_read(&data, port, alt_edid_id, + igt_kms_get_alt_edid()); + } + + connector_subtest("dp-hpd-after-suspend", DisplayPort) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); + + connector_subtest("dp-hpd-after-hibernate", DisplayPort) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES); + + connector_subtest("dp-hpd-storm", DisplayPort) + test_hpd_storm_detect(&data, port, + HPD_STORM_PULSE_INTERVAL_DP); + + connector_subtest("dp-hpd-storm-disable", DisplayPort) + test_hpd_storm_disable(&data, port, + HPD_STORM_PULSE_INTERVAL_DP); + + connector_subtest("dp-edid-change-during-suspend", DisplayPort) + test_suspend_resume_edid_change(&data, port, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE, + edid_id, alt_edid_id); + + connector_subtest("dp-edid-change-during-hibernate", DisplayPort) + test_suspend_resume_edid_change(&data, port, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES, + edid_id, alt_edid_id); + + connector_subtest("dp-crc-single", DisplayPort) + test_display_crc(&data, port, 1, false); + + connector_subtest("dp-crc-fast", DisplayPort) + test_display_crc(&data, port, 1, true); + + connector_subtest("dp-crc-multiple", DisplayPort) + test_display_crc(&data, port, 3, false); + + connector_subtest("dp-frame-dump", DisplayPort) + test_display_frame_dump(&data, port); + } + + igt_subtest_group { + igt_fixture { + require_connector_present( + &data, DRM_MODE_CONNECTOR_HDMIA); + } + + connector_subtest("hdmi-hpd", HDMIA) + test_basic_hotplug(&data, port, + HPD_TOGGLE_COUNT_DP_HDMI); + + connector_subtest("hdmi-hpd-fast", HDMIA) + test_basic_hotplug(&data, port, + HPD_TOGGLE_COUNT_FAST); + + connector_subtest("hdmi-edid-read", HDMIA) { + test_edid_read(&data, port, edid_id, + igt_kms_get_base_edid()); + test_edid_read(&data, port, alt_edid_id, + igt_kms_get_alt_edid()); + } + + connector_subtest("hdmi-hpd-after-suspend", HDMIA) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); + + connector_subtest("hdmi-hpd-after-hibernate", HDMIA) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES); + + connector_subtest("hdmi-hpd-storm", HDMIA) + test_hpd_storm_detect(&data, port, + HPD_STORM_PULSE_INTERVAL_HDMI); + + connector_subtest("hdmi-hpd-storm-disable", HDMIA) + test_hpd_storm_disable(&data, port, + HPD_STORM_PULSE_INTERVAL_HDMI); + + connector_subtest("hdmi-edid-change-during-suspend", HDMIA) + test_suspend_resume_edid_change(&data, port, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE, + edid_id, alt_edid_id); + + connector_subtest("hdmi-edid-change-during-hibernate", HDMIA) + test_suspend_resume_edid_change(&data, port, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES, + edid_id, alt_edid_id); + + connector_subtest("hdmi-crc-single", HDMIA) + test_display_crc(&data, port, 1, false); + + connector_subtest("hdmi-crc-fast", HDMIA) + test_display_crc(&data, port, 1, true); + + connector_subtest("hdmi-crc-multiple", HDMIA) + test_display_crc(&data, port, 3, false); + + connector_subtest("hdmi-frame-dump", HDMIA) + test_display_frame_dump(&data, port); + } + + igt_subtest_group { + igt_fixture { + require_connector_present( + &data, DRM_MODE_CONNECTOR_VGA); + } + + connector_subtest("vga-hpd", VGA) + test_basic_hotplug(&data, port, HPD_TOGGLE_COUNT_VGA); + + connector_subtest("vga-hpd-fast", VGA) + test_basic_hotplug(&data, port, HPD_TOGGLE_COUNT_FAST); + + connector_subtest("vga-edid-read", VGA) { + test_edid_read(&data, port, edid_id, + igt_kms_get_base_edid()); + test_edid_read(&data, port, alt_edid_id, + igt_kms_get_alt_edid()); + } + + connector_subtest("vga-hpd-after-suspend", VGA) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); + + connector_subtest("vga-hpd-after-hibernate", VGA) + test_suspend_resume_hpd(&data, port, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES); + + connector_subtest("vga-hpd-without-ddc", VGA) + test_hpd_without_ddc(&data, port); + + connector_subtest("vga-frame-dump", VGA) + test_analog_frame_dump(&data, port); + } + + igt_subtest_group { + igt_subtest("common-hpd-after-suspend") + test_suspend_resume_hpd_common(&data, + SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); + + igt_subtest("common-hpd-after-hibernate") + test_suspend_resume_hpd_common(&data, + SUSPEND_STATE_DISK, + SUSPEND_TEST_DEVICES); + } + + igt_fixture { + igt_display_fini(&data.display); + close(data.drm_fd); + } +} -- cgit v1.2.3