/* * Copyright © 2020 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. * * Author: * Karthik B S */ #include "igt.h" #define MAX_HDISPLAY_PER_PIPE 5120 IGT_TEST_DESCRIPTION("Test big joiner"); typedef struct { int drm_fd; igt_display_t display; struct igt_fb fb; int mode_number; int n_pipes; uint32_t big_joiner_output_id; } data_t; static void test_invalid_modeset(data_t *data) { drmModeModeInfo *mode; igt_display_t *display = &data->display; igt_output_t *output, *big_joiner_output = NULL, *second_output = NULL; int width = 0, height = 0, i, ret; igt_pipe_t *pipe; igt_plane_t *plane; for_each_connected_output(display, output) { mode = &output->config.connector->modes[0]; if (data->big_joiner_output_id == output->id) { mode = &output->config.connector->modes[data->mode_number]; big_joiner_output = output; } else if (second_output == NULL) { second_output = output; } width = max(width, mode->hdisplay); height = max(height, mode->vdisplay); } igt_create_pattern_fb(data->drm_fd, width, height, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &data->fb); for_each_pipe(display, i) { if (i < (data->n_pipes - 1)) { igt_output_set_pipe(big_joiner_output, i); mode = &big_joiner_output->config.connector->modes[data->mode_number]; igt_output_override_mode(big_joiner_output, mode); pipe = &display->pipes[i]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, &data->fb); igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay); igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay); igt_display_commit2(display, COMMIT_ATOMIC); igt_output_set_pipe(second_output, i + 1); mode = igt_output_get_mode(second_output); pipe = &display->pipes[i + 1]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, &data->fb); igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay); igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay); /* This commit is expectd to fail as this pipe is being used for big joiner */ ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); igt_assert_lt(ret, 0); igt_output_set_pipe(big_joiner_output, PIPE_NONE); igt_output_set_pipe(second_output, PIPE_NONE); pipe = &display->pipes[i]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); /* * Do not explicitly set the plane of the second output to NULL, * as it is the adjacent pipe to the big joiner output and * setting the big joiner plane to NULL will take care of this. */ igt_plane_set_fb(plane, NULL); igt_display_commit2(display, COMMIT_ATOMIC); igt_output_override_mode(big_joiner_output, NULL); } } for_each_pipe(display, i) { if (i < (data->n_pipes - 1)) { igt_output_set_pipe(second_output, i + 1); mode = igt_output_get_mode(second_output); pipe = &display->pipes[i + 1]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, &data->fb); igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay); igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay); igt_display_commit2(display, COMMIT_ATOMIC); igt_output_set_pipe(big_joiner_output, i); mode = &big_joiner_output->config.connector->modes[data->mode_number]; igt_output_override_mode(big_joiner_output, mode); pipe = &display->pipes[i]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, &data->fb); igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay); igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay); /* This commit is expected to fail as the adjacent pipe is already in use*/ ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); igt_assert_lt(ret, 0); igt_output_set_pipe(big_joiner_output, PIPE_NONE); igt_output_set_pipe(second_output, PIPE_NONE); igt_plane_set_fb(plane, NULL); pipe = &display->pipes[i + 1]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, NULL); igt_display_commit2(display, COMMIT_ATOMIC); igt_output_override_mode(big_joiner_output, NULL); } } igt_remove_fb(data->drm_fd, &data->fb); } static void test_basic_modeset(data_t *data) { drmModeModeInfo *mode; igt_output_t *output, *big_joiner_output = NULL; igt_display_t *display = &data->display; int width = 0, height = 0, i; igt_pipe_t *pipe; igt_plane_t *plane; for_each_connected_output(display, output) { if (data->big_joiner_output_id == output->id) { mode = &output->config.connector->modes[data->mode_number]; big_joiner_output = output; width = mode->hdisplay; height = mode->vdisplay; break; } } igt_create_pattern_fb(data->drm_fd, width, height, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &data->fb); for_each_pipe(display, i) { if (i < (data->n_pipes - 1)) { igt_output_set_pipe(big_joiner_output, i); mode = &big_joiner_output->config.connector->modes[data->mode_number]; igt_output_override_mode(big_joiner_output, mode); pipe = &display->pipes[i]; plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(plane, &data->fb); igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay); igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay); igt_display_commit2(display, COMMIT_ATOMIC); igt_output_set_pipe(big_joiner_output, PIPE_NONE); igt_plane_set_fb(plane, NULL); igt_display_commit2(display, COMMIT_ATOMIC); } } igt_remove_fb(data->drm_fd, &data->fb); } igt_main { data_t data; bool big_joiner_mode_found = false; igt_output_t *output; drmModeModeInfo *mode; int valid_output = 0, i; igt_fixture { data.drm_fd = drm_open_driver_master(DRIVER_INTEL); kmstest_set_vt_graphics_mode(); igt_display_require(&data.display, data.drm_fd); for_each_connected_output(&data.display, output) { if (!big_joiner_mode_found) { for (i = 0; i < output->config.connector->count_modes; i++) { mode = &output->config.connector->modes[i]; if (mode->hdisplay > MAX_HDISPLAY_PER_PIPE) { big_joiner_mode_found = true; data.mode_number = i; data.big_joiner_output_id = output->id; break; } } } valid_output++; } data.n_pipes = 0; for_each_pipe(&data.display, i) data.n_pipes++; igt_require_f(big_joiner_mode_found, "No output with 5k+ mode found\n"); } igt_describe("Verify the basic modeset on big joiner mode on all pipes"); igt_subtest("basic") test_basic_modeset(&data); igt_describe("Verify if the modeset on the adjoining pipe is rejected " "when the pipe is active with a big joiner modeset"); igt_subtest("invalid-modeset") { igt_require_f(valid_output > 1, "No valid Second output found\n"); test_invalid_modeset(&data); } igt_fixture igt_display_fini(&data.display); }