summaryrefslogtreecommitdiff
path: root/tests/amdgpu
diff options
context:
space:
mode:
authorEryk Brol <eryk.brol@amd.com>2021-09-16 21:27:16 +0800
committerRodrigo Siqueira <Rodrigo.Siqueira@amd.com>2021-09-28 10:59:11 -0400
commit18278534c085c35adcf62f158a8d5356e5496f8d (patch)
tree77c08dfccd95a589316743ab56be3bef3bbf12e4 /tests/amdgpu
parentcc27789ea0a79b8d052c6728509ec8dd401da347 (diff)
tests/amdgpu: Add amd_link_settings test
[Why] Having a test that iterates through different link settings and performs link training with them is useful and currently missing from IGT. [How] Add a link settings test and its required helper functions. Signed-off-by: Stylon Wang <stylon.wang@amd.com> Signed-off-by: Eryk Brol <eryk.brol@amd.com> Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com> Tested-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Diffstat (limited to 'tests/amdgpu')
-rw-r--r--tests/amdgpu/amd_link_settings.c280
-rw-r--r--tests/amdgpu/meson.build1
2 files changed, 281 insertions, 0 deletions
diff --git a/tests/amdgpu/amd_link_settings.c b/tests/amdgpu/amd_link_settings.c
new file mode 100644
index 00000000..7822683d
--- /dev/null
+++ b/tests/amdgpu/amd_link_settings.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "igt_amd.h"
+
+typedef struct
+{
+ int drm_fd;
+ igt_display_t display;
+ igt_plane_t *primary;
+ igt_output_t *output;
+ igt_fb_t fb;
+ igt_pipe_crc_t *pipe_crc;
+ igt_pipe_t *pipe;
+ enum pipe pipe_id;
+ int connector_type;
+ int w, h;
+ igt_crc_t crc_640_480;
+} data_t;
+
+drmModeModeInfo mode_640_480 = {
+ .name = "640x480",
+ .vrefresh = 60,
+ .clock = 25200,
+
+ .hdisplay = 640,
+ .hsync_start = 656,
+ .hsync_end = 752,
+ .htotal = 800,
+
+ .vdisplay = 480,
+ .vsync_start = 490,
+ .vsync_end = 492,
+ .vtotal = 525,
+
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+const enum dc_lane_count lane_count_values[] =
+{
+ LANE_COUNT_ONE,
+ LANE_COUNT_TWO,
+ LANE_COUNT_FOUR,
+};
+
+const enum dc_link_rate dp_link_rate_values[] =
+{
+ LINK_RATE_LOW,
+ LINK_RATE_HIGH,
+ LINK_RATE_HIGH2,
+ LINK_RATE_HIGH3
+};
+
+const enum dc_link_rate edp_link_rate_values[] =
+{
+ LINK_RATE_LOW,
+ LINK_RATE_HIGH,
+ LINK_RATE_RBR2,
+ LINK_RATE_HIGH2
+};
+
+static void test_fini(data_t *data)
+{
+ igt_pipe_crc_free(data->pipe_crc);
+ igt_display_reset(&data->display);
+}
+
+static void set_all_output_pipe_to_none(data_t *data)
+{
+ igt_output_t *output;
+
+ for_each_connected_output(&data->display, output) {
+ igt_output_set_pipe(output, PIPE_NONE);
+ }
+
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+}
+
+static void test_init(data_t *data, igt_output_t *output)
+{
+ enum pipe pipe;
+
+ igt_require(output->config.connector->count_modes >= 1);
+
+ set_all_output_pipe_to_none(data);
+
+ for_each_pipe(&data->display, pipe) {
+ if (igt_pipe_connector_valid(pipe, output)) {
+ data->pipe_id = pipe;
+ break;
+ }
+ }
+
+ data->connector_type = output->config.connector->connector_type;
+
+ igt_require(data->pipe_id != PIPE_NONE);
+
+ data->pipe = &data->display.pipes[data->pipe_id];
+ data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe_id, "auto");
+
+ igt_output_set_pipe(output, data->pipe_id);
+
+ data->primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+}
+
+static void run_link_training_config(data_t *data, igt_output_t *output)
+{
+ int lane_count[4], link_rate[4], link_spread[4];
+ int max_lc, max_lr;
+ const int current = 0;
+ const int verified = 1;
+ char *connector_name = output->name;
+ igt_crc_t crc;
+ const enum dc_link_rate *link_rate_values;
+ int num_link_rates;
+ if (data->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+ link_rate_values = dp_link_rate_values;
+ num_link_rates = ARRAY_SIZE(dp_link_rate_values);
+ } else if (data->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ link_rate_values = edp_link_rate_values;
+ num_link_rates = ARRAY_SIZE(edp_link_rate_values);
+ } else {
+ igt_info("Not a DP or eDP connector\n");
+ return;
+ }
+
+ igt_amd_read_link_settings(data->drm_fd, connector_name, lane_count,
+ link_rate, link_spread);
+
+ max_lc = lane_count[verified];
+ max_lr = link_rate[verified];
+
+ for (int i = 0; i < ARRAY_SIZE(lane_count_values); i++)
+ {
+ if (lane_count_values[i] > max_lc)
+ continue;
+
+ for (int j = 0; j < num_link_rates; j++)
+ {
+ if (link_rate_values[j] > max_lr)
+ continue;
+
+ /* Write link settings */
+ igt_info("Applying lane count: %d, link rate 0x%02x, on default training\n",
+ lane_count_values[i], link_rate_values[j]);
+ igt_amd_write_link_settings(data->drm_fd, connector_name,
+ lane_count_values[i],
+ link_rate_values[j],
+ LINK_TRAINING_DEFAULT);
+
+ /* Commit */
+ igt_create_pattern_fb(data->drm_fd, mode_640_480.hdisplay,
+ mode_640_480.vdisplay, DRM_FORMAT_XRGB8888,
+ 0, &data->fb);
+ igt_plane_set_fb(data->primary, &data->fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ /* Verify */
+ igt_amd_read_link_settings(data->drm_fd, connector_name,
+ lane_count, link_rate,
+ link_spread);
+
+ /* Collect CRC after writing settings */
+ igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
+ igt_assert_crc_equal(&crc, &data->crc_640_480);
+
+ igt_assert(lane_count[current] == lane_count_values[i]);
+ igt_assert(link_rate[current] == link_rate_values[j]);
+
+ }
+ }
+}
+
+static void test_link_training_configs(data_t *data)
+{
+ const drmModeModeInfo *orig_mode;
+ igt_output_t *output;
+ int lane_count[4], link_rate[4], link_spread[4];
+ int orig_lc, orig_lr;
+ const int current = 0;
+
+ igt_enable_connectors(data->drm_fd);
+
+ for_each_connected_output(&data->display, output) {
+ if (!igt_amd_output_has_link_settings(data->drm_fd, output->name)) {
+ igt_info("Skipping output: %s\n", output->name);
+ continue;
+ }
+
+ igt_info("Testing on output: %s\n", output->name);
+
+ /* Init only if display supports link_settings */
+ test_init(data, output);
+
+ orig_mode = igt_output_get_mode(output);
+ igt_assert(orig_mode);
+
+ /* Collect original mode's LC and LR */
+ igt_amd_read_link_settings(data->drm_fd, output->name, lane_count,
+ link_rate, link_spread);
+ orig_lc = lane_count[current];
+ orig_lr = link_rate[current];
+
+ /* Collect 640x480 CRC */
+ igt_create_pattern_fb(data->drm_fd, mode_640_480.hdisplay,
+ mode_640_480.vdisplay, DRM_FORMAT_XRGB8888,
+ 0, &data->fb);
+ igt_plane_set_fb(data->primary, &data->fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_pipe_crc_collect_crc(data->pipe_crc, &data->crc_640_480);
+
+ /* Change link settings. */
+ run_link_training_config(data, output);
+
+ /* Revert mode back. */
+ igt_output_override_mode(output, orig_mode);
+ igt_info("%s: Reverting to lane count: %d, link rate: 0x%02x\n", output->name, orig_lc, orig_lr);
+ igt_amd_write_link_settings(data->drm_fd, output->name, orig_lc, orig_lr,
+ LINK_TRAINING_DEFAULT);
+
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_remove_fb(data->drm_fd, &data->fb);
+ }
+
+ test_fini(data);
+}
+
+igt_main
+{
+ data_t data;
+ memset(&data, 0, sizeof(data));
+
+ igt_skip_on_simulation();
+
+ igt_fixture
+ {
+ data.drm_fd = drm_open_driver_master(DRIVER_AMDGPU);
+ if (data.drm_fd == -1)
+ igt_skip("Not an amdgpu driver.\n");
+
+ kmstest_set_vt_graphics_mode();
+
+ igt_display_require(&data.display, data.drm_fd);
+ igt_require(data.display.is_atomic);
+ igt_display_require_output(&data.display);
+ }
+
+ igt_describe("Retrieves all link settings configurations and retrains "
+ "links on all possible configurations with different "
+ "types of link training.");
+ igt_subtest("link-training-configs")
+ test_link_training_configs(&data);
+
+ igt_fixture
+ {
+ igt_display_fini(&data.display);
+ }
+}
diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
index 805eb299..aec71cb5 100644
--- a/tests/amdgpu/meson.build
+++ b/tests/amdgpu/meson.build
@@ -13,6 +13,7 @@ if libdrm_amdgpu.found()
'amd_prime',
'amd_module_load',
'amd_mem_leak',
+ 'amd_link_settings',
'amd_vrr_range',
]
amdgpu_deps += libdrm_amdgpu