[igt-dev] [PATCH v4 2/2] tests/amdgpu: Introduces DP DSC test
Rodrigo Siqueira
Rodrigo.Siqueira at amd.com
Tue Dec 7 16:43:31 UTC 2021
From: Eryk Brol <eryk.brol at amd.com>
This commit adds a DP DSC test that checks:
* Forces DSC on/off and ensures it is reset properly
* Check DSC slice height property
* Verify various DSC slice dimensions
* Tests various combinations of link_rate + lane_count and logs if DSC
enabled/disabled Tests different bpc settings and logs if DSC is
enabled/disabled
Change since V2:
- Remove IGT_CRTC_DSC_SLICE_HEIGHT crtc property from this commit
Change since V1:
- Rebase
Cc: Harry Wentland <harry.wentland at amd.com>
Cc: Nicholas Choi <Nicholas.Choi at amd.com>
Cc: Mark Yacoub <markyacoub at chromium.org>
Cc: Hayden Goodfellow <hayden.goodfellow at amd.com>
Cc: Hersen Wu <hersenxs.wu at amd.com>
Cc: Roman Li <roman.li at amd.com>
Signed-off-by: Mikita Lipski <mikita.lipski at amd.com>
Signed-off-by: Eryk Brol <eryk.brol at amd.com>
---
lib/igt_amd.c | 494 +++++++++++++++++++++++++--
lib/igt_amd.h | 35 ++
tests/amdgpu/amd_dp_dsc.c | 685 ++++++++++++++++++++++++++++++++++++++
tests/amdgpu/meson.build | 1 +
4 files changed, 1193 insertions(+), 22 deletions(-)
create mode 100644 tests/amdgpu/amd_dp_dsc.c
diff --git a/lib/igt_amd.c b/lib/igt_amd.c
index f1bfb421..4bcfd594 100644
--- a/lib/igt_amd.c
+++ b/lib/igt_amd.c
@@ -251,11 +251,11 @@ bool igt_amd_is_tiled(uint64_t modifier)
}
/**
- * igt_amd_output_has_hpd: check if connector has HPD debugfs entry
+ * igt_amd_output_has_dsc: check if connector has dsc debugfs entry
* @drm_fd: DRM file descriptor
* @connector_name: The connector's name, on which we're reading the status
*/
-static bool igt_amd_output_has_hpd(int drm_fd, char *connector_name)
+static bool igt_amd_output_has_dsc(int drm_fd, char *connector_name)
{
int fd;
int res;
@@ -267,9 +267,9 @@ static bool igt_amd_output_has_hpd(int drm_fd, char *connector_name)
return false;
}
- res = fstatat(fd, DEBUGFS_HPD_TRIGGER, &stat, 0);
+ res = fstatat(fd, DEBUGFS_DSC_CLOCK_EN , &stat, 0);
if (res != 0) {
- igt_info("%s debugfs not supported\n", DEBUGFS_HPD_TRIGGER);
+ igt_info("%s debugfs not supported\n", DEBUGFS_DSC_CLOCK_EN);
close(fd);
return false;
}
@@ -279,49 +279,499 @@ static bool igt_amd_output_has_hpd(int drm_fd, char *connector_name)
}
/**
- * igt_amd_require_hpd: Checks if connectors have HPD debugfs
+ * is_dp_dsc_supported: Checks if connector is DSC capable
+ * @display: A pointer to an #igt_display_t structure
+ * @drm_fd: DRM file descriptor
+ */
+bool is_dp_dsc_supported(int drm_fd, char *connector_name)
+{
+ char buf[512];
+ int fd, ret;
+
+ 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 false;
+ }
+
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_FEC_SUPPORT, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_FEC_SUPPORT, connector_name);
+
+ return strstr(buf, "DSC_Sink_Support: yes");
+}
+
+/**
+ * is_dp_fec_supported: Checks if connector is FEC capable
+ * @display: A pointer to an #igt_display_t structure
+ * @drm_fd: DRM file descriptor
+ */
+bool is_dp_fec_supported(int drm_fd, char *connector_name)
+{
+ char buf[512];
+ int fd, ret;
+
+ 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 false;
+ }
+
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_FEC_SUPPORT, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_FEC_SUPPORT, connector_name);
+
+ return strstr(buf, "FEC_Sink_Support: yes");
+}
+
+/**
+ * igt_amd_require_dsc: Checks if connectors have DSC debugfs
* @display: A pointer to an #igt_display_t structure
* @drm_fd: DRM file descriptor
*
- * Checks if the AMDGPU driver has support the 'trigger_hotplug'
- * entry for HPD. Skip test if HPD is not supported.
+ * Checks if the AMDGPU driver has support of debugfs entries for
+ * DSC. Skip test if DSC is not supported.
*/
-void igt_amd_require_hpd(igt_display_t *display, int drm_fd)
+void igt_amd_require_dsc(igt_display_t *display, int drm_fd)
{
igt_output_t *output;
for_each_connected_output(display, output) {
- if (igt_amd_output_has_hpd(drm_fd, output->name))
+ if (igt_amd_output_has_dsc(drm_fd, output->name))
return;
}
- igt_skip("No HPD debugfs support.\n");
+ igt_skip("No DSC debugfs support.\n");
}
/**
- * igt_amd_trigger_hotplut: Triggers a debugfs HPD
+ * igt_amd_read_dsc_clock_status: Read the DSC Clock Enable debugfs
* @drm_fd: DRM file descriptor
- * @connector_name: The connector's name, which we trigger the hotplug on
+ * @connector_name: The connector's name, which we use to read status on
*
- * igt_amd_require_hpd should be called before calling this.
*/
-int igt_amd_trigger_hotplug(int drm_fd, char *connector_name)
+int igt_amd_read_dsc_clock_status(int drm_fd, char *connector_name)
+{
+ char buf[4];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_CLOCK_EN, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_CLOCK_EN, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+
+/**
+ * igt_amd_write_dsc_clock_en: Write the DSC Clock Enable debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ * @dsc_force: DSC force parameter, 0 - DSC automatic, 1 - DSC force on,
+ * 2 - DSC force off
+ *
+ */
+void igt_amd_write_dsc_clock_en(int drm_fd, char *connector_name, int dsc_force)
+{
+ int fd, dsc_fd;
+ char src[4];
+ int wr_len;
+
+ fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
+ igt_assert(fd >= 0);
+ dsc_fd = openat(fd, DEBUGFS_DSC_CLOCK_EN, O_WRONLY);
+ close(fd);
+ igt_assert(dsc_fd >= 0);
+
+ if (dsc_force == DSC_FORCE_ON)
+ snprintf(src, sizeof(src), "%d", 1);
+ else if (dsc_force == DSC_FORCE_OFF)
+ snprintf(src, sizeof(src), "%d", 2);
+ else
+ snprintf(src, sizeof(src), "%d", 0);
+
+ igt_info("DSC Clock force, write %s > dsc_clock_en\n", src);
+
+ wr_len = write(dsc_fd, src, strlen(src));
+ close(dsc_fd);
+ igt_assert_eq(wr_len, strlen(src));
+}
+
+/**
+ * igt_amd_write_dsc_param_slice_height: Write the DSC Slice Height debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ * @slice_height: DSC slice height parameter, accepts any positive integer,
+ * if parameter is negative - it will not write to debugfs.
+ *
+ */
+void igt_amd_write_dsc_param_slice_height(int drm_fd, char *connector_name, int slice_height)
+{
+ int fd, dsc_fd;
+ char src[32];
+ int wr_len;
+
+ fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
+ igt_assert(fd >= 0);
+ dsc_fd = openat(fd, DEBUGFS_DSC_SLICE_HEIGHT, O_WRONLY);
+ close(fd);
+ igt_assert(dsc_fd >= 0);
+
+ if (slice_height >= 0) {
+ snprintf(src, sizeof(src), "%#x", slice_height);
+ } else {
+ igt_warn("DSC SLICE HEIGHT, slice height parameter is invalid (%d)\n", slice_height);
+ goto exit;
+ }
+
+ igt_info("DSC SLICE HEIGHT, write %s > dsc_slice_height\n", src);
+
+ wr_len = write(dsc_fd, src, strlen(src));
+ igt_assert_eq(wr_len, strlen(src));
+exit:
+ close(dsc_fd);
+}
+
+/**
+ * igt_amd_read_dsc_param_slice_height: Read the DSC Slice Height debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_slice_height(int drm_fd, char *connector_name)
+{
+ char buf[32];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_SLICE_HEIGHT, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_SLICE_HEIGHT, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_write_dsc_param_slice_width: Write the DSC Slice Width debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ * @slice_width: DSC slice width parameter, accepts any positive integer,
+ * if parameter is negative - it will not write to debugfs.
+ *
+ */
+void igt_amd_write_dsc_param_slice_width(int drm_fd, char *connector_name, int slice_width)
{
- int fd, hpd_fd;
+ int fd, dsc_fd;
+ char src[32];
int wr_len;
- const char *enable_hpd = "1";
fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
igt_assert(fd >= 0);
- hpd_fd = openat(fd, DEBUGFS_HPD_TRIGGER, O_WRONLY);
+ dsc_fd = openat(fd, DEBUGFS_DSC_SLICE_WIDTH, O_WRONLY);
+ close(fd);
+ igt_assert(dsc_fd >= 0);
+
+ if (slice_width >= 0) {
+ snprintf(src, sizeof(src), "%#x", slice_width);
+ } else {
+ igt_warn("DSC SLICE WIDTH, slice width parameter is invalid (%d)\n", slice_width);
+ goto exit;
+ }
+
+ igt_info("DSC SLICE WIDTH, write %s > dsc_slice_width\n", src);
+
+ wr_len = write(dsc_fd, src, strlen(src));
+ igt_assert_eq(wr_len, strlen(src));
+exit:
+ close(dsc_fd);
+}
+
+/**
+ * igt_amd_read_dsc_param_slice_width: Read the DSC Slice Width debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_slice_width(int drm_fd, char *connector_name)
+{
+ char buf[32];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_SLICE_WIDTH, buf, sizeof(buf));
close(fd);
- igt_assert(hpd_fd >= 0);
- wr_len = write(hpd_fd, enable_hpd, strlen(enable_hpd));
- close(hpd_fd);
- igt_assert_eq(wr_len, strlen(enable_hpd));
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_SLICE_WIDTH, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_write_dsc_param_bpp: Write the DSC Bits Per Pixel debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ * @bpp: DSC bits per pixel parameter, accepts any positive integer,
+ * if parameter is negative - it will not write to debugfs.
+ *
+ */
+void igt_amd_write_dsc_param_bpp(int drm_fd, char *connector_name, int bpp)
+{
+ int fd, dsc_fd;
+ char src[32];
+ int wr_len;
+
+ fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
+ igt_assert(fd >= 0);
+ dsc_fd = openat(fd, DEBUGFS_DSC_BITS_PER_PIXEL, O_WRONLY);
+ close(fd);
+ igt_assert(dsc_fd >= 0);
+
+ if (bpp >= 0) {
+ snprintf(src, sizeof(src), "%#x", bpp);
+ } else {
+ igt_warn("DSC BITS PER PIXEL, bits per pixel parameter is invalid (%d)\n", bpp);
+ goto exit;
+ }
+
+ igt_info("DSC BITS PER PIXEL, write %s > dsc_bits_per_pixel\n", src);
+
+ wr_len = write(dsc_fd, src, strlen(src));
+ igt_assert_eq(wr_len, strlen(src));
+exit:
+ close(dsc_fd);
+}
+
+/**
+ * igt_amd_read_dsc_param_bpp: Read the DSC Bits Per Pixel debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_bpp(int drm_fd, char *connector_name)
+{
+ char buf[32];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_BITS_PER_PIXEL, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_BITS_PER_PIXEL, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_read_dsc_param_pic_width: Read the DSC Picture Width debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_pic_width(int drm_fd, char *connector_name)
+{
+ char buf[4];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_PIC_WIDTH, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_PIC_WIDTH, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_read_dsc_param_pic_height: Read the DSC Picture Height debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_pic_height(int drm_fd, char *connector_name)
+{
+ char buf[4];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_PIC_HEIGHT, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_PIC_HEIGHT, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_read_dsc_param_chunk_size: Read the DSC Chunk Size debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_chunk_size(int drm_fd, char *connector_name)
+{
+ char buf[4];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_CHUNK_SIZE, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_CHUNK_SIZE, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_read_dsc_param_slice_bpg: Read the DSC Slice BPG Offset debugfs
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we use to read status on
+ *
+ */
+int igt_amd_read_dsc_param_slice_bpg(int drm_fd, char *connector_name)
+{
+ char buf[4];
+ int fd, ret;
+
+ 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 false;
+ }
+ ret = igt_debugfs_simple_read(fd, DEBUGFS_DSC_SLICE_BPG, buf, sizeof(buf));
+ close(fd);
+
+ igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
+ DEBUGFS_DSC_SLICE_BPG, connector_name);
+
+ return strtol(buf, NULL, 0);
+}
+
+/**
+ * igt_amd_output_has_hpd: check if connector has HPD debugfs entry
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, on which we're reading the status
+ */
+static bool igt_amd_output_has_hpd(int drm_fd, char *connector_name)
+{
+ int fd;
+ int res;
+ struct stat stat;
+
+ 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;
+ }
+
+ res = fstatat(fd, DEBUGFS_HPD_TRIGGER, &stat, 0);
+ if (res != 0) {
+ igt_info("%s debugfs not supported\n", DEBUGFS_HPD_TRIGGER);
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+
+/**
+ * igt_amd_require_hpd: Checks if connectors have HPD debugfs
+ * @display: A pointer to an #igt_display_t structure
+ * @drm_fd: DRM file descriptor
+ *
+ * Checks if the AMDGPU driver has support the 'trigger_hotplug'
+ * entry for HPD. Skip test if HPD is not supported.
+ */
+void igt_amd_require_hpd(igt_display_t *display, int drm_fd)
+{
+ igt_output_t *output;
+
+ for_each_connected_output(display, output) {
+ if (igt_amd_output_has_hpd(drm_fd, output->name))
+ return;
+ }
+
+ igt_skip("No HPD debugfs support.\n");
+}
+
+/**
+ * igt_amd_trigger_hotplut: Triggers a debugfs HPD
+ * @drm_fd: DRM file descriptor
+ * @connector_name: The connector's name, which we trigger the hotplug on
+ *
+ * igt_amd_require_hpd should be called before calling this.
+ */
+int igt_amd_trigger_hotplug(int drm_fd, char *connector_name)
+{
+ int fd, hpd_fd;
+ int wr_len;
+ const char *enable_hpd = "1";
+
+ fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
+ igt_assert(fd >= 0);
+ hpd_fd = openat(fd, DEBUGFS_HPD_TRIGGER, O_WRONLY);
+ close(fd);
+ igt_assert(hpd_fd >= 0);
+
+ wr_len = write(hpd_fd, enable_hpd, strlen(enable_hpd));
+ close(hpd_fd);
+ igt_assert_eq(wr_len, strlen(enable_hpd));
- return 0;
+ return 0;
}
/*
diff --git a/lib/igt_amd.h b/lib/igt_amd.h
index e5bdbf33..7a91cbff 100644
--- a/lib/igt_amd.h
+++ b/lib/igt_amd.h
@@ -27,9 +27,27 @@
#include "igt.h"
#include "igt_fb.h"
+/* Read & Write DSC parameters */
+#define DEBUGFS_DSC_CLOCK_EN "dsc_clock_en"
+#define DEBUGFS_DSC_SLICE_WIDTH "dsc_slice_width"
+#define DEBUGFS_DSC_SLICE_HEIGHT "dsc_slice_height"
+#define DEBUGFS_DSC_BITS_PER_PIXEL "dsc_bits_per_pixel"
+/* Read only DSC parameters */
+#define DEBUGFS_DSC_PIC_WIDTH "dsc_pic_width"
+#define DEBUGFS_DSC_PIC_HEIGHT "dsc_pic_height"
+#define DEBUGFS_DSC_CHUNK_SIZE "dsc_chunk_size"
+#define DEBUGFS_DSC_SLICE_BPG "dsc_slice_bpg"
+#define DEBUGFS_DSC_FEC_SUPPORT "dp_dsc_fec_support"
+
#define DEBUGFS_DP_LINK_SETTINGS "link_settings"
#define DEBUGFS_HPD_TRIGGER "trigger_hotplug"
+enum amd_dsc_clock_force {
+ DSC_AUTOMATIC = 0,
+ DSC_FORCE_ON,
+ DSC_FORCE_OFF,
+};
+
enum dc_lane_count {
LANE_COUNT_UNKNOWN = 0,
LANE_COUNT_ONE = 1,
@@ -80,6 +98,23 @@ void igt_amd_fb_convert_plane_to_tiled(struct igt_fb *dst, void *dst_buf,
struct igt_fb *src, void *src_buf);
bool igt_amd_is_tiled(uint64_t modifier);
+/* IGT DSC helper functions */
+bool is_dp_dsc_supported(int drm_fd, char *connector_name);
+bool is_dp_fec_supported(int drm_fd, char *connector_name);
+void igt_amd_require_dsc(igt_display_t *display, int drm_fd);
+int igt_amd_read_dsc_clock_status(int drm_fd, char *connector_name);
+void igt_amd_write_dsc_clock_en(int drm_fd, char *connector_name, int dsc_force);
+void igt_amd_write_dsc_param_slice_height(int drm_fd, char *connector_name, int slice_height);
+int igt_amd_read_dsc_param_slice_height(int drm_fd, char *connector_name);
+void igt_amd_write_dsc_param_slice_width(int drm_fd, char *connector_name, int slice_width);
+int igt_amd_read_dsc_param_slice_width(int drm_fd, char *connector_name);
+void igt_amd_write_dsc_param_bpp(int drm_fd, char *connector_name, int bpp);
+int igt_amd_read_dsc_param_bpp(int drm_fd, char *connector_name);
+int igt_amd_read_dsc_param_pic_width(int drm_fd, char *connector_name);
+int igt_amd_read_dsc_param_pic_height(int drm_fd, char *connector_name);
+int igt_amd_read_dsc_param_chunk_size(int drm_fd, char *connector_name);
+int igt_amd_read_dsc_param_slice_bpg(int drm_fd, char *connector_name);
+
/* IGT HPD helper functions */
void igt_amd_require_hpd(igt_display_t *display, int drm_fd);
int igt_amd_trigger_hotplug(int drm_fd, char *connector_name);
diff --git a/tests/amdgpu/amd_dp_dsc.c b/tests/amdgpu/amd_dp_dsc.c
new file mode 100644
index 00000000..d73425e2
--- /dev/null
+++ b/tests/amdgpu/amd_dp_dsc.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright 2021 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"
+#include "sw_sync.h"
+#include <fcntl.h>
+#include <signal.h>
+
+#define NUM_SLICE_SLOTS 4
+
+/* Maximumm pipes on any AMD ASIC. */
+#define MAX_PIPES 6
+
+/* Common test data. */
+typedef struct data {
+ igt_display_t display;
+ igt_plane_t *primary[MAX_PIPES];
+ igt_output_t *output[MAX_PIPES];
+ igt_pipe_t *pipe[MAX_PIPES];
+ igt_pipe_crc_t *pipe_crc[MAX_PIPES];
+ drmModeModeInfo mode[MAX_PIPES];
+ enum pipe pipe_id[MAX_PIPES];
+ int fd;
+} data_t;
+
+/* BPC connector state. */
+typedef struct output_bpc {
+ unsigned int current;
+ unsigned int maximum;
+} output_bpc_t;
+
+/* Common test cleanup. */
+static void test_fini(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ int i;
+
+ for (i = 0; i < display->n_pipes; ++i) {
+ igt_pipe_crc_free(data->pipe_crc[i]);
+ }
+
+ igt_display_reset(display);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+}
+
+/* Common test setup. */
+static void test_init(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ int i, n;
+
+ for (i = 0; i < display->n_pipes; ++i) {
+ data->pipe_id[i] = PIPE_A + i;
+ data->pipe[i] = &data->display.pipes[data->pipe_id[i]];
+ data->primary[i] = igt_pipe_get_plane_type(
+ data->pipe[i], DRM_PLANE_TYPE_PRIMARY);
+ data->pipe_crc[i] =
+ igt_pipe_crc_new(data->fd, data->pipe_id[i], "auto");
+ }
+
+ for (i = 0, n = 0; i < display->n_outputs && n < display->n_pipes; ++i) {
+ igt_output_t *output = &display->outputs[i];
+ data->output[n] = output;
+
+ /* Only allow physically connected displays for the tests. */
+ if (!igt_output_is_connected(output))
+ continue;
+
+ /* Ensure that outpus are DP, DSC & FEC capable*/
+ if (!(is_dp_fec_supported(data->fd, output->name) &&
+ is_dp_dsc_supported(data->fd, output->name)))
+ continue;
+
+ if (output->config.connector->connector_type !=
+ DRM_MODE_CONNECTOR_DisplayPort)
+ continue;
+
+ igt_assert(kmstest_get_connector_default_mode(
+ data->fd, output->config.connector, &data->mode[n]));
+
+ n += 1;
+ }
+
+ igt_display_reset(display);
+}
+
+static void test_dsc_enable(data_t *data)
+{
+ bool dsc_on, dsc_after, dsc_before;
+ igt_display_t *display = &data->display;
+ igt_output_t *output;
+ igt_fb_t ref_fb;
+ int i, test_conn_cnt = 0;
+
+ test_init(data);
+ igt_enable_connectors(data->fd);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ /* Setup the output */
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ igt_create_pattern_fb(data->fd,
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ DRM_FORMAT_XRGB8888,
+ 0,
+ &ref_fb);
+ igt_output_set_pipe(output, data->pipe_id[i]);
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+ test_conn_cnt++;
+
+ /* Save pipe's initial DSC state */
+ dsc_before = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ /* Force enable DSC */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_ON);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ /* Check if DSC is enabled */
+ dsc_on = igt_amd_read_dsc_clock_status(data->fd, output->name) == 1;
+
+ /* Revert DSC to automatic state */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_OFF);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display,DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ dsc_after = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ /* Revert DSC back to automatic mechanism by disabling state overwrites*/
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_AUTOMATIC);
+
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_assert_f(dsc_on, "Enabling DSC on pipe failed.\n");
+ igt_assert_f(dsc_after == dsc_before, "Reverting DSC to initial state failed.\n");
+
+ /* Cleanup fb */
+ igt_remove_fb(data->fd, &ref_fb);
+ }
+
+ test_fini(data);
+ igt_skip_on(test_conn_cnt == 0);
+}
+
+static void test_dsc_slice_height_property(data_t *data)
+{
+ bool dsc_on, dsc_after, dsc_before;
+ int slice_height_on, slice_height_off;
+ igt_display_t *display = &data->display;
+ igt_output_t *output;
+ igt_fb_t ref_fb;
+ int i, test_conn_cnt = 0;
+
+ test_init(data);
+ igt_enable_connectors(data->fd);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ /* Setup the output */
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ igt_create_pattern_fb(data->fd,
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ DRM_FORMAT_XRGB8888,
+ 0,
+ &ref_fb);
+ igt_output_set_pipe(output, data->pipe_id[i]);
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+ test_conn_cnt++;
+
+ /* Save pipe's initial DSC state */
+ dsc_before = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ /* Force enable DSC */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_ON);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ /* Check if DSC is enabled */
+ dsc_on = igt_amd_read_dsc_clock_status(data->fd, output->name) == 1;
+
+ slice_height_on = igt_pipe_get_prop(display, data->pipe_id[i], IGT_CRTC_DSC_SLICE_HEIGHT);
+
+ /* Revert DSC to automatic state */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_OFF);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ dsc_after = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ slice_height_off = igt_pipe_get_prop(display, data->pipe_id[i], IGT_CRTC_DSC_SLICE_HEIGHT);
+
+ /* Revert DSC back to automatic mechanism by disabling state overwrites*/
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_AUTOMATIC);
+
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_assert_f(dsc_on, "Enabling DSC on pipe failed.\n");
+ igt_assert_f(slice_height_on > 0, "DSC Slice property was not set properly.\n");
+ igt_assert_f(dsc_after == dsc_before, "Reverting DSC to initial state failed.\n");
+ igt_assert_f(slice_height_off == 0, "DSC Slice property was not reset properly.\n");
+
+ /* Cleanup fb */
+ igt_remove_fb(data->fd, &ref_fb);
+ }
+
+ test_fini(data);
+ igt_skip_on(test_conn_cnt == 0);
+}
+
+static bool update_slice_height(data_t *data, int v_addressable,
+ int *num_slices, igt_output_t *output, int conn_idx, igt_fb_t ref_fb)
+{
+ int i;
+ bool pass = true;
+
+ for(i = 0; i < NUM_SLICE_SLOTS; i++) {
+ int act_slice_height;
+ int slice_height = v_addressable / num_slices[i] + (v_addressable % num_slices[i]);
+
+ /* Overwrite DSC slice height */
+ igt_amd_write_dsc_param_slice_height(data->fd, output->name, slice_height);
+ igt_plane_set_fb(data->primary[conn_idx], &ref_fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_info("Forcing slice height: slice height %d num slices vertical %d\n", slice_height, num_slices[i]);
+
+ act_slice_height = igt_amd_read_dsc_param_slice_height(data->fd, output->name);
+
+ igt_info("Reading slice height: actual slice height %d VS assigned slice height %d\n", act_slice_height, slice_height);
+
+ pass = (slice_height == act_slice_height);
+
+ if (!pass)
+ break;
+ }
+
+ igt_amd_write_dsc_param_slice_height(data->fd, output->name, 0);
+ igt_plane_set_fb(data->primary[conn_idx], &ref_fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ return pass;
+}
+
+static bool update_slice_width(data_t *data, int h_addressable,
+ int *num_slices, igt_output_t *output, int conn_idx, igt_fb_t ref_fb)
+{
+ int i;
+ bool pass = true;
+
+ for(i = 0; i < NUM_SLICE_SLOTS; i++) {
+ int act_slice_width;
+ int slice_width = h_addressable / num_slices[i] + (h_addressable % num_slices[i]);
+
+ /* Overwrite DSC slice width */
+ igt_amd_write_dsc_param_slice_width(data->fd, output->name, slice_width);
+ igt_plane_set_fb(data->primary[conn_idx], &ref_fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_info("Forcing slice width: slice width %d num slices horisontal %d\n", slice_width, num_slices[i]);
+
+ act_slice_width = igt_amd_read_dsc_param_slice_width(data->fd, output->name);
+
+ igt_info("Reading slice width: actual slice width %d VS assigned slice width %d\n", act_slice_width, slice_width);
+
+ pass = (slice_width == act_slice_width);
+
+ if (!pass)
+ break;
+ }
+
+ igt_amd_write_dsc_param_slice_width(data->fd, output->name, 0);
+ igt_plane_set_fb(data->primary[conn_idx], &ref_fb);
+ igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ return pass;
+}
+
+static void test_dsc_slice_dimensions_change(data_t *data)
+{
+ bool dsc_on, dsc_after, dsc_before;
+ igt_output_t *output;
+ igt_display_t *display = &data->display;
+ igt_fb_t ref_fb;
+ int num_slices [] = { 1, 2, 4, 8 };
+ int h_addressable, v_addressable;
+ bool ret_slice_height= false, ret_slice_width = false;
+ int i, test_conn_cnt = 0;
+
+ test_init(data);
+ igt_enable_connectors(data->fd);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ /* Setup the output */
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ igt_create_pattern_fb(data->fd,
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ DRM_FORMAT_XRGB8888,
+ 0,
+ &ref_fb);
+ igt_output_set_pipe(output, data->pipe_id[i]);
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+ test_conn_cnt++;
+
+ h_addressable = data->mode->hdisplay;
+ v_addressable = data->mode->vdisplay;
+
+ igt_info("Mode info: v_ative %d h_active %d\n", v_addressable, h_addressable);
+
+ /* Save pipe's initial DSC state */
+ dsc_before = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ /* Force enable DSC */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_ON);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ /* Check if DSC is enabled */
+ dsc_on = igt_amd_read_dsc_clock_status(data->fd, output->name) == 1;
+
+ if (dsc_on) {
+ ret_slice_height = update_slice_height(data, v_addressable, num_slices, output, i, ref_fb);
+ ret_slice_width = update_slice_width(data, h_addressable, num_slices, output, i, ref_fb);
+ }
+
+ /* Force disable DSC */
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_FORCE_OFF);
+
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ dsc_after = igt_amd_read_dsc_clock_status(data->fd, output->name);
+
+ /* Revert DSC back to automatic mechanism by disabling state overwrites*/
+ igt_plane_set_fb(data->primary[i], &ref_fb);
+
+ igt_amd_write_dsc_clock_en(data->fd, output->name, DSC_AUTOMATIC);
+
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ igt_assert_f(dsc_on, "Enabling DSC on pipe failed.\n");
+ igt_assert_f(ret_slice_height, "Changing slice height failed.\n");
+ igt_assert_f(ret_slice_width, "Changing slice width failed.\n");
+ igt_assert_f(dsc_after == dsc_before, "Reverting DSC to initial state failed.\n");
+
+ /* Cleanup fb */
+ igt_remove_fb(data->fd, &ref_fb);
+ }
+
+ test_fini(data);
+ igt_skip_on(test_conn_cnt == 0);
+}
+
+static void test_dsc_link_settings(data_t *data)
+{
+ igt_output_t *output;
+ igt_fb_t ref_fb[MAX_PIPES];
+ igt_crc_t ref_crc[MAX_PIPES], new_crc[MAX_PIPES];
+ int lane_count[4], link_rate[4], link_spread[4];
+ igt_display_t *display = &data->display;
+ int i, lc, lr;
+ bool dsc_on;
+ const enum dc_lane_count lane_count_vals[] =
+ {
+ LANE_COUNT_TWO,
+ LANE_COUNT_FOUR
+ };
+ const enum dc_link_rate link_rate_vals[] =
+ {
+ LINK_RATE_LOW,
+ LINK_RATE_HIGH,
+ LINK_RATE_HIGH2,
+ LINK_RATE_HIGH3
+ };
+
+ test_init(data);
+
+ /* Setup all outputs */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ igt_create_pattern_fb(data->fd,
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ DRM_FORMAT_XRGB8888,
+ 0,
+ &ref_fb[i]);
+ igt_output_set_pipe(output, data->pipe_id[i]);
+ igt_plane_set_fb(data->primary[i], &ref_fb[i]);
+ }
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+ /* Collect reference CRCs */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ igt_pipe_crc_collect_crc(data->pipe_crc[i], &ref_crc[i]);
+ }
+
+ for (lc = 0; lc < ARRAY_SIZE(lane_count_vals); lc++) {
+ for (lr = 0; lr < ARRAY_SIZE(link_rate_vals); lr++) {
+ /* Write new link_settings */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ /* Write lower link settings */
+ igt_info("Applying lane count: %d, link rate 0x%02x, on default training\n",
+ lane_count_vals[lc], link_rate_vals[lr]);
+ igt_amd_write_link_settings(data->fd, output->name,
+ lane_count_vals[lc],
+ link_rate_vals[lr],
+ LINK_TRAINING_DEFAULT);
+ usleep(500 * MSEC_PER_SEC);
+ }
+
+ /* Trigger commit after writing new link settings */
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ /* Verify lower link settings */
+ igt_amd_read_link_settings(data->fd, output->name,
+ lane_count,
+ link_rate,
+ link_spread);
+
+ igt_assert_f(lane_count[0] == lane_count_vals[lc], "Lowering lane count settings failed\n");
+ igt_assert_f(link_rate[0] == link_rate_vals[lr], "Lowering link rate settings failed\n");
+
+ /* Log current mode and DSC status */
+ dsc_on = igt_amd_read_dsc_clock_status(data->fd, output->name) == 1;
+ igt_info("Current mode is: %dx%d @%dHz -- DSC is: %s\n",
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ data->mode[i].vrefresh,
+ dsc_on ? "ON" : "OFF");
+
+ igt_pipe_crc_collect_crc(data->pipe_crc[i], &new_crc[i]);
+ igt_assert_crc_equal(&ref_crc[i], &new_crc[i]);
+ }
+ }
+ }
+
+ /* Cleanup all fbs */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+ igt_remove_fb(data->fd, &ref_fb[i]);
+ }
+
+ test_fini(data);
+}
+
+/* Returns the current and maximum bpc from the connector debugfs. */
+static output_bpc_t get_output_bpc(int data_fd, char *connector_name)
+{
+ char buf[256];
+ char *start_loc;
+ int fd, res;
+ output_bpc_t info;
+
+ fd = igt_debugfs_connector_dir(data_fd, connector_name, O_RDONLY);
+ igt_assert(fd >= 0);
+
+ res = igt_debugfs_simple_read(fd, "output_bpc", buf, sizeof(buf));
+
+ igt_require(res > 0);
+
+ close(fd);
+
+ igt_assert(start_loc = strstr(buf, "Current: "));
+ igt_assert_eq(sscanf(start_loc, "Current: %u", &info.current), 1);
+
+ igt_assert(start_loc = strstr(buf, "Maximum: "));
+ igt_assert_eq(sscanf(start_loc, "Maximum: %u", &info.maximum), 1);
+
+ return info;
+}
+
+/* Verifies that connector has the correct output bpc */
+static void assert_output_bpc(int data_fd, char *connector_name, unsigned int bpc)
+{
+ output_bpc_t info = get_output_bpc(data_fd, connector_name);
+
+ igt_require_f(info.maximum >= bpc,
+ "Monitor doesn't support %u bpc, max is %u\n", bpc,
+ info.maximum);
+
+ igt_assert_eq(info.current, bpc);
+}
+
+/* Returns the highest bpc this dispaly supports */
+static int get_max_supported_bpc(int data_fd, char *connector_name)
+{
+ output_bpc_t info = get_output_bpc(data_fd, connector_name);
+ return info.maximum;
+}
+
+static void test_dsc_bpc(data_t *data)
+{
+ igt_output_t *output;
+ igt_fb_t ref_fb[MAX_PIPES];
+ igt_crc_t test_crc;
+ igt_display_t *display = &data->display;
+ int i, bpc, max_supported_bpc[MAX_PIPES];
+ bool dsc_on;
+ const int bpc_vals[] = {12, 10, 8};
+
+ test_init(data);
+
+ /* Find max supported bpc */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+ igt_info("Checking bpc support of conn %s\n", output->name);
+ max_supported_bpc[i] = get_max_supported_bpc(data->fd, output->name);
+ }
+
+ /* Setup all outputs */
+ for (bpc = 0; bpc < ARRAY_SIZE(bpc_vals); bpc++) {
+ igt_info("Testing bpc = %d\n", bpc_vals[bpc]);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ if (max_supported_bpc[i] < bpc_vals[bpc]) {
+ igt_info("Display doesn't support bpc of %d, max is %d. Skipping to next bpc value.\n", bpc_vals[bpc], max_supported_bpc[i]);
+ continue;
+ }
+ igt_info("Setting bpc = %d\n", bpc_vals[bpc]);
+ igt_output_set_prop_value(output, IGT_CONNECTOR_MAX_BPC, bpc_vals[bpc]);
+ igt_create_pattern_fb(data->fd,
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ DRM_FORMAT_XRGB8888,
+ 0,
+ &ref_fb[i]);
+ igt_output_set_pipe(output, data->pipe_id[i]);
+ igt_plane_set_fb(data->primary[i], &ref_fb[i]);
+ }
+
+ igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
+
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ if (max_supported_bpc[i] < bpc_vals[bpc])
+ continue;
+
+ /* Check that crc is non-zero */
+ igt_pipe_crc_collect_crc(data->pipe_crc[i], &test_crc);
+ igt_assert(test_crc.crc[0] && test_crc.crc[1] && test_crc.crc[2]);
+
+ /* Check current bpc */
+ igt_info("Verifying display %s has correct bpc\n", output->name);
+ assert_output_bpc(data->fd, output->name, bpc_vals[bpc]);
+
+ /* Log current mode and DSC status */
+ dsc_on = igt_amd_read_dsc_clock_status(data->fd, output->name) == 1;
+ igt_info("Current mode is: %dx%d @%dHz -- DSC is: %s\n",
+ data->mode[i].hdisplay,
+ data->mode[i].vdisplay,
+ data->mode[i].vrefresh,
+ dsc_on ? "ON" : "OFF");
+ }
+
+ /* Cleanup all fbs */
+ for (i = 0; i < display->n_pipes; i++) {
+ output = data->output[i];
+ if (!output || !igt_output_is_connected(output))
+ continue;
+
+ if (max_supported_bpc[i] < bpc_vals[bpc])
+ continue;
+
+ igt_remove_fb(data->fd, &ref_fb[i]);
+ }
+ }
+
+ test_fini(data);
+}
+
+igt_main
+{
+ data_t data = { 0 };
+
+ igt_skip_on_simulation();
+
+ igt_fixture
+ {
+ data.fd = drm_open_driver_master(DRIVER_ANY);
+
+ igt_display_require(&data.display, data.fd);
+ igt_require(data.display.is_atomic);
+ igt_display_require_output(&data.display);
+
+ igt_amd_require_dsc(&data.display, data.fd);
+ kmstest_set_vt_graphics_mode();
+ }
+
+ igt_describe("Forces DSC on/off & ensures it is reset properly");
+ igt_subtest("dsc-enable-basic")
+ test_dsc_enable(&data);
+
+ igt_describe("Tests DSC slice height property & ensures it is reset properly on DSC enable/disable");
+ igt_subtest("dsc-slice-height-property")
+ test_dsc_slice_height_property(&data);
+
+ igt_describe("Tests various DSC slice dimensions");
+ igt_subtest("dsc-slice-dimensions-change")
+ test_dsc_slice_dimensions_change(&data);
+
+ igt_describe("Tests various combinations of link_rate + lane_count and logs if DSC enabled/disabled");
+ igt_subtest("dsc-link-settings")
+ test_dsc_link_settings(&data);
+
+ igt_describe("Tests different bpc settings and logs if DSC is enabled/disabled");
+ igt_subtest("dsc-bpc")
+ test_dsc_bpc(&data);
+
+ igt_fixture
+ {
+ igt_reset_connectors();
+ igt_display_fini(&data.display);
+ }
+}
diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
index d232e490..d8e8ddfb 100644
--- a/tests/amdgpu/meson.build
+++ b/tests/amdgpu/meson.build
@@ -17,6 +17,7 @@ if libdrm_amdgpu.found()
'amd_link_settings',
'amd_vrr_range',
'amd_mode_switch',
+ 'amd_dp_dsc',
'amd_psr',
'amd_plane',
]
--
2.25.1
More information about the igt-dev
mailing list