[PATCH i-g-t, v5] tests/amdgpu/amd_replay: Add amd_replay IGT test
Leo Li
sunpeng.li at amd.com
Wed Aug 7 18:18:28 UTC 2024
On 2024-08-07 03:17, Tom Chung wrote:
> [why]
> Add a basic IGT test for panel replay feature.
>
> [how]
> Subtest case
>
> a. static screen
> 1. Check if system support panel replay.
> 2. Start video flip for a while.
> 3. Stop video flip and wait for a while.
> 4. Check if replay state is in Replay mode.
>
> b. Live mode (intermittent)
> 1. Check if system support panel replay.
> 2. Start video flip for a while.
> 3. Check if replay state is in Live mode.
> 4. Stop video flip and wait for a while.
> 5. Check if replay state is in Replay mode.
> 6. Repaet 2 to 5.
>
> c. Live mode (constant)
> 1. Check if system support panel replay.
> 2. Start video flip for a while.
> 3. Check if replay state is in Live mode.
>
> d. Resume from Suspend
> 1. Suspend the system and resume
> 2. Start video flip for a while.
> 3. Stop video flip and wait for a while.
> 4. Check if replay state is in Replay mode.
>
> Cc: Leo Li <sunpeng.li at amd.com>
> Signed-off-by: Tom Chung <chiahsuan.chung at amd.com>
Reviewed-by: Leo Li <sunpeng.li at amd.com>
Thanks!
> ---
> v2: Modify the include header files in tests/amdgpu/amd_replay.c
> v3: Fix some coding style issues. Add a new subtest case.
> v4: 1. Update enum replay_state and include file.
> 2. Modify the return value of igt_amd_read_replay_state()
> 3. Add a page_flip_test() to simplify the test function
> v5: Modify the bool page_flip_test() to void page_flip_test()
>
> lib/igt_amd.c | 163 ++++++++++++++
> lib/igt_amd.h | 41 +++-
> tests/amdgpu/amd_replay.c | 456 ++++++++++++++++++++++++++++++++++++++
> tests/amdgpu/meson.build | 1 +
> 4 files changed, 660 insertions(+), 1 deletion(-)
> create mode 100644 tests/amdgpu/amd_replay.c
>
> diff --git a/lib/igt_amd.c b/lib/igt_amd.c
> index 149af5151..3ddb5f403 100644
> --- a/lib/igt_amd.c
> +++ b/lib/igt_amd.c
> @@ -1014,6 +1014,169 @@ bool igt_amd_output_has_ilr_setting(int drm_fd, char *connector_name)
> return igt_amd_output_has_debugfs(drm_fd, connector_name, DEBUGFS_EDP_ILR_SETTING);
> }
>
> +/**
> + * igt_amd_output_has_replay_cap: check if eDP connector has replay_capability debugfs entry
> + * @drm_fd: DRM file descriptor
> + * @connector_name: The connector's name, on which we're reading the status
> + */
> +bool igt_amd_output_has_replay_cap(int drm_fd, char *connector_name)
> +{
> + return igt_amd_output_has_debugfs(drm_fd, connector_name, DEBUGFS_EDP_REPLAY_CAP);
> +}
> +
> +/**
> + * igt_amd_replay_support_sink: check if sink device support Panel Replay
> + * @drm_fd: DRM file descriptor
> + * @connector_name: The connector's name, on which we're reading the status
> + */
> +bool igt_amd_replay_support_sink(int drm_fd, char *connector_name)
> +{
> + char buf[128];
> + int ret;
> + int fd;
> +
> + fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
> + if (fd < 0) {
> + igt_info("output %s: debugfs not found\n", connector_name);
> +
> + return false;
> + }
> +
> + ret = igt_debugfs_simple_read(fd, DEBUGFS_EDP_REPLAY_CAP, buf, sizeof(buf));
> + igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
> + DEBUGFS_EDP_REPLAY_CAP, connector_name);
> + close(fd);
> +
> + if (ret < 1)
> + return false;
> +
> + return strstr(buf, "Sink support: yes");
> +}
> +
> +/**
> + * igt_amd_replay_support_drv: check if driver support Panel Replay
> + * @drm_fd: DRM file descriptor
> + * @connector_name: The connector's name, on which we're reading the status
> + */
> +bool igt_amd_replay_support_drv(int drm_fd, char *connector_name)
> +{
> + char buf[128];
> + int ret;
> + int fd;
> +
> + fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
> + if (fd < 0) {
> + igt_info("output %s: debugfs not found\n", connector_name);
> +
> + return false;
> + }
> +
> + ret = igt_debugfs_simple_read(fd, DEBUGFS_EDP_REPLAY_CAP, buf, sizeof(buf));
> + igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
> + DEBUGFS_EDP_REPLAY_CAP, connector_name);
> + close(fd);
> +
> + if (ret < 1)
> + return false;
> +
> + return strstr(buf, "Driver support: yes") && strstr(buf, "Config support: yes");
> +}
> +
> +/**
> + * igt_amd_output_has_replay_state: check if eDP connector has replay_state debugfs entry
> + * @drm_fd: DRM file descriptor
> + * @connector_name: The connector's name, on which we're reading the status
> + */
> +bool igt_amd_output_has_replay_state(int drm_fd, char *connector_name)
> +{
> + return igt_amd_output_has_debugfs(drm_fd, connector_name, DEBUGFS_EDP_REPLAY_STATE);
> +}
> +
> +/*
> + * Convert raw panel replay state to emum panel replay state.
> + */
> +static enum replay_state convert_replay_state(uint32_t raw_state)
> +{
> + switch (raw_state) {
> + case 0:
> + return REPLAY_STATE_0;
> + case 0x10:
> + return REPLAY_STATE_1;
> + case 0x11:
> + return REPLAY_STATE_1A;
> + case 0x20:
> + return REPLAY_STATE_2;
> + case 0x21:
> + return REPLAY_STATE_2A;
> + case 0x30:
> + return REPLAY_STATE_3;
> + case 0x31:
> + return REPLAY_STATE_3INIT;
> + case 0x40:
> + return REPLAY_STATE_4;
> + case 0x41:
> + return REPLAY_STATE_4A;
> + case 0x42:
> + return REPLAY_STATE_4B;
> + case 0x43:
> + return REPLAY_STATE_4C;
> + case 0x44:
> + return REPLAY_STATE_4D;
> + case 0x45:
> + return REPLAY_STATE_4E;
> + case 0x4A:
> + return REPLAY_STATE_4B_LOCKED;
> + case 0x4B:
> + return REPLAY_STATE_4C_UNLOCKED;
> + case 0x50:
> + return REPLAY_STATE_5;
> + case 0x51:
> + return REPLAY_STATE_5A;
> + case 0x52:
> + return REPLAY_STATE_5B;
> + case 0x5A:
> + return REPLAY_STATE_5A_LOCKED;
> + case 0x5B:
> + return REPLAY_STATE_5B_UNLOCKED;
> + case 0x60:
> + return REPLAY_STATE_6;
> + case 0x61:
> + return REPLAY_STATE_6A;
> + case 0x62:
> + return REPLAY_STATE_6B;
> + default:
> + return REPLAY_STATE_INVALID;
> + }
> +}
> +
> +/**
> + * @brief Read Panel Replay State from debugfs interface
> + * @param drm_fd DRM file descriptor
> + * @param connector_name The connector's name, on which we're reading the status
> + * @return Panel Replay state
> + */
> +enum replay_state igt_amd_read_replay_state(int drm_fd, char *connector_name)
> +{
> + char buf[4];
> + int fd, ret, raw_state;
> +
> + fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
> + if (fd < 0) {
> + igt_info("Couldn't open connector %s debugfs directory\n", connector_name);
> +
> + return -1;
> + }
> +
> + ret = igt_debugfs_simple_read(fd, DEBUGFS_EDP_REPLAY_STATE, buf, sizeof(buf));
> + close(fd);
> +
> + igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
> + DEBUGFS_EDP_REPLAY_STATE, connector_name);
> +
> + raw_state = strtol(buf, NULL, 10);
> + return convert_replay_state(raw_state);
> +}
> +
> /**
> * igt_amd_output_has_psr_cap: check if eDP connector has psr_capability debugfs entry
> * @drm_fd: DRM file descriptor
> diff --git a/lib/igt_amd.h b/lib/igt_amd.h
> index 6780b99de..bce4657cb 100644
> --- a/lib/igt_amd.h
> +++ b/lib/igt_amd.h
> @@ -47,6 +47,8 @@
> #define DEBUGFS_EDP_ILR_SETTING "ilr_setting"
> #define MAX_SUPPORTED_ILR 8
> #define MULTIPLIER_TO_LR 270000
> +#define DEBUGFS_EDP_REPLAY_CAP "replay_capability"
> +#define DEBUGFS_EDP_REPLAY_STATE "replay_state"
> #define DEBUGFS_EDP_PSR_CAP "psr_capability"
> #define DEBUGFS_EDP_PSR_STATE "psr_state"
> #define DEBUGFS_ALLOW_EDP_HOTPLUG_DETECT "allow_edp_hotplug_detection"
> @@ -100,6 +102,37 @@ enum dc_link_training_type {
> LINK_TRAINING_NO_PATTERN
> };
>
> +/*
> + * enumeration of REPLAY STATE below should be aligned to the upstreamed
> + * amdgpu kernel driver 'enum replay_state' in dmub_cmd.h
> + */
> +enum replay_state {
> + REPLAY_STATE_0 = 0x0,
> + REPLAY_STATE_1 = 0x10,
> + REPLAY_STATE_1A = 0x11,
> + REPLAY_STATE_2 = 0x20,
> + REPLAY_STATE_2A = 0x21,
> + REPLAY_STATE_3 = 0x30,
> + REPLAY_STATE_3INIT = 0x31,
> + REPLAY_STATE_4 = 0x40,
> + REPLAY_STATE_4A = 0x41,
> + REPLAY_STATE_4B = 0x42,
> + REPLAY_STATE_4C = 0x43,
> + REPLAY_STATE_4D = 0x44,
> + REPLAY_STATE_4E = 0x45,
> + REPLAY_STATE_4B_LOCKED = 0x4A,
> + REPLAY_STATE_4C_UNLOCKED = 0x4B,
> + REPLAY_STATE_5 = 0x50,
> + REPLAY_STATE_5A = 0x51,
> + REPLAY_STATE_5B = 0x52,
> + REPLAY_STATE_5A_LOCKED = 0x5A,
> + REPLAY_STATE_5B_UNLOCKED = 0x5B,
> + REPLAY_STATE_6 = 0x60,
> + REPLAY_STATE_6A = 0x61,
> + REPLAY_STATE_6B = 0x62,
> + REPLAY_STATE_INVALID = 0xFF
> +};
> +
> /*
> * enumeration of PSR STATE below should be aligned to the upstreamed
> * amdgpu kernel driver 'enum dc_psr_state' in dc_type.h
> @@ -135,7 +168,8 @@ enum amdgpu_debug_visual_confirm {
> VISUAL_CONFIRM_HDR = 2,
> VISUAL_CONFIRM_MPCTREE = 4,
> VISUAL_CONFIRM_PSR = 5,
> - VISUAL_CONFIRM_SWIZZLE = 9
> + VISUAL_CONFIRM_SWIZZLE = 9,
> + VISUAL_CONFIRM_REPLAY = 12
> };
>
> uint32_t igt_amd_create_bo(int fd, uint64_t size);
> @@ -189,6 +223,11 @@ void igt_amd_write_ilr_setting(
> int drm_fd, char *connector_name, enum dc_lane_count lane_count,
> uint8_t link_rate_set);
> bool igt_amd_output_has_ilr_setting(int drm_fd, char *connector_name);
> +bool igt_amd_output_has_replay_cap(int drm_fd, char *connector_name);
> +bool igt_amd_replay_support_sink(int drm_fd, char *connector_name);
> +bool igt_amd_replay_support_drv(int drm_fd, char *connector_name);
> +bool igt_amd_output_has_replay_state(int drm_fd, char *connector_name);
> +enum replay_state igt_amd_read_replay_state(int drm_fd, char *connector_name);
> bool igt_amd_output_has_psr_cap(int drm_fd, char *connector_name);
> bool igt_amd_psr_support_sink(int drm_fd, char *connector_name, enum psr_mode mode);
> bool igt_amd_psr_support_drv(int drm_fd, char *connector_name, enum psr_mode mode);
> diff --git a/tests/amdgpu/amd_replay.c b/tests/amdgpu/amd_replay.c
> new file mode 100644
> index 000000000..b5bb10b34
> --- /dev/null
> +++ b/tests/amdgpu/amd_replay.c
> @@ -0,0 +1,456 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2024 Advanced Micro Devices, Inc.
> + */
> +
> +#include <dirent.h>
> +#include <fcntl.h>
> +
> +#include "igt_amd.h"
> +
> +/* hardware requirements:
> + * eDP panel that supports Panel Replay
> + */
> +IGT_TEST_DESCRIPTION("Basic test for enabling Panel Replay for eDP displays");
> +
> +#define REPLAY_SETTLE_DELAY 10
> +
> +/* Common test data. */
> +struct test_data {
> + igt_display_t display;
> + igt_plane_t *primary;
> + igt_output_t *output;
> + igt_pipe_t *pipe;
> + drmModeModeInfo *mode;
> + igt_fb_t ref_fb;
> + igt_fb_t ref_fb2;
> + igt_fb_t *flip_fb;
> + enum pipe pipe_id;
> + int fd;
> + int debugfs_fd;
> + int w, h;
> +};
> +
> +struct {
> + bool visual_confirm;
> +} opt = {
> + .visual_confirm = false, /* visual confirm debug option */
> +};
> +
> +const char *help_str =
> +" --visual-confirm Panel Replay visual confirm debug option enable\n";
> +
> +struct option long_options[] = {
> + {"visual-confirm", required_argument, NULL, 'v'},
> + { 0, 0, 0, 0 }
> +};
> +
> +enum test_mode {
> + TEST_MODE_STATIC_SCREEN = 0,
> + TEST_MODE_INTERMITTENT_LIVE,
> + TEST_MODE_CONSTANT_LIVE,
> + TEST_MODE_SUSPEND,
> + TEST_MODE_COUNT
> +};
> +
> +/* Common test setup. */
> +static void test_init(struct test_data *data)
> +{
> + igt_display_t *display = &data->display;
> +
> + /* It doesn't matter which pipe we choose on amdpgu. */
> + data->pipe_id = PIPE_A;
> + data->pipe = &data->display.pipes[data->pipe_id];
> +
> + igt_display_reset(display);
> +
> + data->output = igt_get_single_output_for_pipe(display, data->pipe_id);
> + igt_require(data->output);
> + igt_info("output %s\n", data->output->name);
> +
> + data->mode = igt_output_get_mode(data->output);
> + igt_assert(data->mode);
> + kmstest_dump_mode(data->mode);
> +
> + data->primary =
> + igt_pipe_get_plane_type(data->pipe, DRM_PLANE_TYPE_PRIMARY);
> +
> + igt_output_set_pipe(data->output, data->pipe_id);
> +
> + data->w = data->mode->hdisplay;
> + data->h = data->mode->vdisplay;
> +
> + data->ref_fb.fb_id = 0;
> + data->ref_fb2.fb_id = 0;
> +
> + if (opt.visual_confirm) {
> + /**
> + * if visual confirm option is enabled, we'd trigger a full modeset before test run
> + * to have Panel Replay visual confirm enable take effect. DPMS off -> ON transition
> + * is one of many approaches.
> + */
> + kmstest_set_connector_dpms(data->fd, data->output->config.connector,
> + DRM_MODE_DPMS_OFF);
> + kmstest_set_connector_dpms(data->fd, data->output->config.connector,
> + DRM_MODE_DPMS_ON);
> + }
> +}
> +
> +/* Common test cleanup. */
> +static void test_fini(struct test_data *data)
> +{
> + igt_display_t *display = &data->display;
> +
> + igt_display_reset(display);
> + igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
> +}
> +
> +static int check_conn_type(struct test_data *data, uint32_t type)
> +{
> + int i;
> +
> + for (i = 0; i < data->display.n_outputs; i++) {
> + uint32_t conn_type = data->display.outputs[i].config.connector->connector_type;
> +
> + if (conn_type == type)
> + return i;
> + }
> +
> + return -1;
> +}
> +
> +static bool replay_mode_supported(struct test_data *data)
> +{
> + /* run Panel Replay test if eDP panel support Panel Replay */
> + if (!igt_amd_output_has_replay_cap(data->fd, data->output->name)) {
> + igt_warn(" driver does not have %s debugfs interface\n", DEBUGFS_EDP_REPLAY_CAP);
> +
> + return false;
> + }
> +
> + if (!igt_amd_output_has_replay_state(data->fd, data->output->name)) {
> + igt_warn(" driver does not have %s debugfs interface\n", DEBUGFS_EDP_REPLAY_STATE);
> +
> + return false;
> + }
> +
> + if (!igt_amd_replay_support_sink(data->fd, data->output->name)) {
> + igt_warn(" output %s not support Panel Replay mode\n", data->output->name);
> +
> + return false;
> + }
> +
> + if (!igt_amd_replay_support_drv(data->fd, data->output->name)) {
> + igt_warn(" kernel driver not support Panel Replay mode\n");
> +
> + return false;
> + }
> +
> + return true;
> +}
> +
> +/* Read from /dev/drm_dp_aux
> + * addr: DPCD offset
> + * val: Read value of DPCD register
> + */
> +static bool dpcd_read_byte(int drm_fd,
> + drmModeConnector *connector, uint32_t addr, uint8_t *val)
> +{
> + DIR *dir;
> + int dir_fd;
> + uint8_t buf[16] = {0};
> + *val = 0;
> +
> + dir_fd = igt_connector_sysfs_open(drm_fd, connector);
> + igt_assert(dir_fd >= 0);
> +
> + dir = fdopendir(dir_fd);
> + igt_assert(dir);
> +
> + for (;;) {
> + struct dirent *ent;
> + char path[5 + sizeof(ent->d_name)];
> + int fd, ret, i, j, k;
> +
> + ent = readdir(dir);
> + if (!ent)
> + break;
> +
> + if (strncmp(ent->d_name, "drm_dp_aux", 10))
> + continue;
> +
> + snprintf(path, sizeof(path), "/dev/%s", ent->d_name);
> +
> + fd = open(path, O_RDONLY);
> + igt_assert(fd >= 0);
> +
> + k = (addr / 16) + 1;
> + j = addr % 16;
> +
> + /* read 16 bytes each loop */
> + for (i = 0; i < k; i++) {
> + ret = read(fd, buf, sizeof(buf));
> + if (ret < 0)
> + break;
> + if (ret != sizeof(buf))
> + break;
> + }
> +
> + close(fd);
> +
> + closedir(dir);
> + close(dir_fd);
> +
> + if (ret > 0)
> + *val = buf[j];
> +
> + return (ret > 0);
> + }
> +
> + closedir(dir);
> + close(dir_fd);
> +
> + return false;
> +}
> +
> +static void page_flip_test(struct test_data *data, igt_output_t *output,
> + enum test_mode test_mode, uint32_t frame_num)
> +{
> + int ret, frame_count;
> + enum replay_state replay_state;
> + uint8_t panel_dpcd = 0;
> +
> + if (!data || data->ref_fb.fb_id == 0 || data->ref_fb2.fb_id == 0
> + || frame_num <= 5) {
> + igt_skip("Page flip failed.\n");
> + }
> +
> + data->flip_fb = &data->ref_fb;
> +
> + for (frame_count = 0; frame_count <= frame_num; frame_count++) {
> + ret = drmModePageFlip(data->fd, output->config.crtc->crtc_id,
> + data->flip_fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL);
> + igt_require(ret == 0);
> + kmstest_wait_for_pageflip(data->fd);
> +
> + if (test_mode == (TEST_MODE_CONSTANT_LIVE || TEST_MODE_INTERMITTENT_LIVE)
> + && frame_count > 5) {
> + /* Panel Replay state needs few frame to enter the live mode */
> + replay_state = igt_amd_read_replay_state(data->fd, output->name);
> + dpcd_read_byte(data->fd, output->config.connector, 0x378, &panel_dpcd);
> + igt_debug("replay_state live mode = 0x%X\n", replay_state);
> + igt_fail_on_f(replay_state < REPLAY_STATE_4 && replay_state >= REPLAY_STATE_5,
> + "State should be REPLAY_STATE_4 (Active with single frame update)\n");
> + igt_fail_on_f(panel_dpcd == 0, "Panel is not in replay mode\n");
> + }
> +
> + if (frame_count % 2 == 0)
> + data->flip_fb = &data->ref_fb2;
> + else
> + data->flip_fb = &data->ref_fb;
> + }
> +}
> +
> +static void run_check_replay(struct test_data *data, enum test_mode test_mode)
> +{
> + int edp_idx;
> + enum replay_state replay_state;
> + igt_output_t *output;
> + uint8_t panel_dpcd = 0;
> +
> + test_init(data);
> +
> + edp_idx = check_conn_type(data, DRM_MODE_CONNECTOR_eDP);
> + igt_skip_on_f(edp_idx == -1, "no eDP connector found\n");
> +
> + /* check if eDP support Panel Replay. */
> + igt_skip_on(!replay_mode_supported(data));
> +
> + for_each_connected_output(&data->display, output) {
> + if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_eDP)
> + continue;
> +
> + igt_create_color_fb(data->fd, data->mode->hdisplay,
> + data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0, 0.6, 0.6, 0.6, &data->ref_fb);
> + igt_create_color_fb(data->fd, data->mode->hdisplay,
> + data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0, 0.0, 0.4, 0.14, &data->ref_fb2);
> +
> + igt_plane_set_fb(data->primary, &data->ref_fb);
> + igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
> + data->flip_fb = &data->ref_fb;
> + drmModePageFlip(data->fd, output->config.crtc->crtc_id,
> + data->flip_fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL);
> + kmstest_wait_for_pageflip(data->fd);
> +
> + /* Panel Replay state takes some time to settle its value on static screen */
> + sleep(REPLAY_SETTLE_DELAY);
> +
> + /* Check Panel Replay state */
> + replay_state = igt_amd_read_replay_state(data->fd, output->name);
> + igt_debug("replay_state static mode before flip = 0x%X\n", replay_state);
> + igt_fail_on_f(replay_state < 0, "Open Panel Replay state debugfs failed\n");
> + igt_fail_on_f(replay_state < REPLAY_STATE_2,
> + "Panel Replay was not enabled for connector %s\n", output->name);
> +
> + /* Do some page flip and let the replay go into live mode */
> + page_flip_test(data, output, test_mode, 20);
> +
> + /* Check Panel Replay state in static screen */
> + if (test_mode == TEST_MODE_STATIC_SCREEN || TEST_MODE_INTERMITTENT_LIVE) {
> + /* Panel Replay state takes some time to settle its value on static screen */
> + sleep(1);
> +
> + replay_state = igt_amd_read_replay_state(data->fd, output->name);
> + dpcd_read_byte(data->fd, output->config.connector, 0x378, &panel_dpcd);
> + igt_debug("replay_state static mode = 0x%X\n", replay_state);
> + igt_fail_on_f(replay_state < REPLAY_STATE_3 && replay_state >= REPLAY_STATE_4,
> + "State should be REPLAY_STATE_3 (Active)\n");
> + igt_fail_on_f(panel_dpcd == 0, "Panel is not in replay mode\n");
> + }
> +
> + /* Do another page flip if we do the replay_intermittent_live test */
> + if (test_mode == TEST_MODE_INTERMITTENT_LIVE) {
> + page_flip_test(data, output, test_mode, 30);
> +
> + /* Panel Replay state takes some time to settle its value on static screen */
> + sleep(1);
> +
> + replay_state = igt_amd_read_replay_state(data->fd, output->name);
> + dpcd_read_byte(data->fd, output->config.connector, 0x378, &panel_dpcd);
> + igt_debug("replay_state TEST_MODE_INTERMITTENT_LIVE after flip = 0x%X\n",
> + replay_state);
> + igt_fail_on_f(replay_state < REPLAY_STATE_3 && replay_state >= REPLAY_STATE_4,
> + "State should be REPLAY_STATE_3 (Active)\n");
> + igt_fail_on_f(panel_dpcd == 0, "Panel is not in replay mode\n");
> + }
> +
> + igt_remove_fb(data->fd, &data->ref_fb);
> + igt_remove_fb(data->fd, &data->ref_fb2);
> + }
> +
> + test_fini(data);
> +}
> +
> +static void run_check_replay_suspend(struct test_data *data)
> +{
> + int edp_idx;
> + enum replay_state replay_state;
> + igt_output_t *output;
> + uint8_t panel_dpcd = 0;
> +
> + test_init(data);
> +
> + edp_idx = check_conn_type(data, DRM_MODE_CONNECTOR_eDP);
> + igt_skip_on_f(edp_idx == -1, "no eDP connector found\n");
> +
> + /* check if eDP support Panel Replay. */
> + igt_skip_on(!replay_mode_supported(data));
> +
> + for_each_connected_output(&data->display, output) {
> + if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_eDP)
> + continue;
> +
> + igt_create_color_fb(data->fd, data->mode->hdisplay,
> + data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0, 0.6, 0.6, 0.6, &data->ref_fb);
> + igt_create_color_fb(data->fd, data->mode->hdisplay,
> + data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0, 0.0, 0.4, 0.14, &data->ref_fb2);
> +
> + igt_plane_set_fb(data->primary, &data->ref_fb);
> + igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
> + data->flip_fb = &data->ref_fb;
> + drmModePageFlip(data->fd, output->config.crtc->crtc_id,
> + data->flip_fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL);
> + kmstest_wait_for_pageflip(data->fd);
> +
> + /* Suspend and Resume */
> + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE);
> +
> + /* Do some page flip and let the replay go into live mode */
> + page_flip_test(data, output, TEST_MODE_SUSPEND, 10);
> +
> + /* Panel Replay state takes some time to settle its value on static screen */
> + sleep(REPLAY_SETTLE_DELAY);
> +
> + replay_state = igt_amd_read_replay_state(data->fd, output->name);
> + dpcd_read_byte(data->fd, output->config.connector, 0x378, &panel_dpcd);
> + igt_debug("replay_state static mode = 0x%X\n", replay_state);
> + igt_fail_on_f(replay_state < REPLAY_STATE_3 && replay_state >= REPLAY_STATE_4,
> + "State should be REPLAY_STATE_3 (Active)\n");
> + igt_fail_on_f(panel_dpcd == 0, "Panel is not in replay mode\n");
> +
> + igt_remove_fb(data->fd, &data->ref_fb);
> + igt_remove_fb(data->fd, &data->ref_fb2);
> + }
> +
> + test_fini(data);
> +}
> +
> +static int opt_handler(int option, int option_index, void *data)
> +{
> + switch (option) {
> + case 'v':
> + opt.visual_confirm = strtol(optarg, NULL, 0);
> + igt_info("Panel Replay Visual Confirm %s\n",
> + opt.visual_confirm ? "enabled" : "disabled");
> + break;
> + default:
> + return IGT_OPT_HANDLER_ERROR;
> + }
> +
> + return IGT_OPT_HANDLER_SUCCESS;
> +}
> +
> +igt_main_args("", long_options, help_str, opt_handler, NULL)
> +{
> + struct test_data data;
> +
> + igt_skip_on_simulation();
> + memset(&data, 0, sizeof(data));
> +
> + igt_fixture
> + {
> + data.fd = drm_open_driver_master(DRIVER_AMDGPU);
> +
> + if (data.fd == -1)
> + igt_skip("Not an amdgpu driver.\n");
> +
> + data.debugfs_fd = igt_debugfs_dir(data.fd);
> +
> + kmstest_set_vt_graphics_mode();
> +
> + igt_display_require(&data.display, data.fd);
> + igt_require(&data.display.is_atomic);
> + igt_display_require_output(&data.display);
> +
> + /* check if visual confirm option available */
> + if (opt.visual_confirm) {
> + igt_skip_on(!igt_amd_has_visual_confirm(data.fd));
> + igt_skip_on_f(!igt_amd_set_visual_confirm(data.fd, VISUAL_CONFIRM_REPLAY),
> + "set Panel Replay visual confirm failed\n");
> + }
> + }
> +
> + igt_describe("Test whether Panel Replay can be enabled with static screen");
> + igt_subtest("replay_static_screen") run_check_replay(&data, TEST_MODE_STATIC_SCREEN);
> +
> + igt_describe("Test whether Panel Replay can be enabled with intermittent live mdoe");
> + igt_subtest("replay_intermittent_live") run_check_replay(&data, TEST_MODE_INTERMITTENT_LIVE);
> +
> + igt_describe("Test whether Panel Replay can be enabled with constant live mdoe");
> + igt_subtest("replay_constant_live") run_check_replay(&data, TEST_MODE_CONSTANT_LIVE);
> +
> + igt_describe("Test whether Panel Replay can be enabled after resume from suspend");
> + igt_subtest("replay_suspend") run_check_replay_suspend(&data);
> +
> + igt_fixture
> + {
> + if (opt.visual_confirm) {
> + igt_skip_on(!igt_amd_has_visual_confirm(data.fd));
> + igt_require_f(igt_amd_set_visual_confirm(data.fd, VISUAL_CONFIRM_DISABLE),
> + "reset Panel Replay visual confirm failed\n");
> + }
> + close(data.debugfs_fd);
> + igt_display_fini(&data.display);
> + drm_close_driver(data.fd);
> + }
> +}
> diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
> index 36d65f44b..7d40f788b 100644
> --- a/tests/amdgpu/meson.build
> +++ b/tests/amdgpu/meson.build
> @@ -30,6 +30,7 @@ if libdrm_amdgpu.found()
> 'amd_prime',
> 'amd_psr',
> 'amd_ras',
> + 'amd_replay',
> 'amd_security',
> 'amd_uvd_dec',
> 'amd_uvd_enc',
More information about the igt-dev
mailing list