[PATCH i-g-t] tests/amdgpu/amd_vrr_range: Fix panel cannot light up after test
Tom Chung
chiahsuan.chung at amd.com
Thu Jan 2 10:37:26 UTC 2025
[Why]
If the sink side support VRR, override the EDID may cause sink
side cannot light up.
[How]
Just parsing the VRR range from sink side EDID without override it
if the sink side support VRR.
Signed-off-by: Tom Chung <chiahsuan.chung at amd.com>
---
tests/amdgpu/amd_vrr_range.c | 125 ++++++++++++++++++++++++++++-------
1 file changed, 102 insertions(+), 23 deletions(-)
diff --git a/tests/amdgpu/amd_vrr_range.c b/tests/amdgpu/amd_vrr_range.c
index 79db6f9c4..15bebbfa7 100644
--- a/tests/amdgpu/amd_vrr_range.c
+++ b/tests/amdgpu/amd_vrr_range.c
@@ -29,20 +29,23 @@ IGT_TEST_DESCRIPTION("Test EDID parsing and debugfs reporting on Freesync displa
/* Maximumm pipes on any AMD ASIC. */
#define MAX_PIPES 6
+#define EDID_SIZE 256
+#define EDID_PATH "/sys/class/drm/card0-%s/edid"
/* Common test data. */
+struct vrr_range {
+ unsigned int min;
+ unsigned int max;
+};
+
typedef struct data {
igt_display_t display;
igt_plane_t *primary;
igt_output_t *output[MAX_PIPES];
int fd;
+ struct vrr_range expected_range;
} data_t;
-typedef struct range {
- unsigned int min;
- unsigned int max;
-} range_t;
-
/* Test flags. */
enum {
TEST_NONE = 1 << 0,
@@ -53,7 +56,7 @@ struct {
const char *name;
uint32_t connector_type;
const unsigned char edid[256];
- const range_t range;
+ const struct vrr_range range;
} edid_database[] = {
{
/* EDID Version 1.4. Timing requires 2 DP lanes. */
@@ -212,12 +215,12 @@ static int find_test_edid_index(uint32_t connector_type)
}
/* Returns the min and max vrr range from the connector debugfs. */
-static range_t get_freesync_range(data_t *data, igt_output_t *output)
+static struct vrr_range get_freesync_range(data_t *data, igt_output_t *output)
{
char buf[256];
char *start_loc;
int fd, res;
- range_t range;
+ struct vrr_range range;
fd = igt_debugfs_connector_dir(data->fd, output->name, O_RDONLY);
igt_assert(fd >= 0);
@@ -249,13 +252,84 @@ static void trigger_edid_parse(data_t *data, igt_output_t *output, uint32_t test
usleep(1500000);
}
+/* Returns true if an output supports VRR. */
+static bool has_vrr(igt_output_t *output)
+{
+ return igt_output_has_prop(output, IGT_CONNECTOR_VRR_CAPABLE) &&
+ igt_output_get_prop(output, IGT_CONNECTOR_VRR_CAPABLE);
+}
+
+static void parse_vrr_gange_from_edid(data_t *data, uint8_t *edid, int index)
+{
+ bool max_rate_offset = false;
+ bool min_rate_offset = false;
+
+ /* Check Bytes 4 Vertical rate offsets
+ * Vertical rate offsets:
+ * 00 = none;
+ * 10 = +255 Hz for max. rate;
+ * 11 = +255 Hz for max. and min. rates.
+ */
+ if ((edid[index + 4] & 0b10) == 0b10)
+ max_rate_offset = true;
+ else if ((edid[index + 4] & 0b11) == 0b11) {
+ max_rate_offset = true;
+ min_rate_offset = true;
+ }
+
+ /* Bytes 5 Min vertical field rate (1–255 Hz; 256–510 Hz, if offset).*/
+ data->expected_range.min =
+ min_rate_offset ? edid[index + 5] + 255 : edid[index + 5];
+ /* Bytes 6 Max vertical field rate (1–255 Hz; 256–510 Hz, if offset).*/
+ data->expected_range.max =
+ max_rate_offset ? edid[index + 6] + 255 : edid[index + 6];
+}
+
+static bool find_vrr_range_from_edid(data_t *data, igt_output_t *output)
+{
+ char edid_path[PATH_MAX] = "\0";
+ uint8_t sink_edid[EDID_SIZE] = "\0";
+ const uint8_t range_limits_head[4] = {0x00, 0x00, 0x00, 0xFD};
+ const unsigned int range_head_size = sizeof(range_limits_head);
+ int fd, i, read_size, index = 0;
+
+ /* Get EDID */
+ igt_assert(snprintf(edid_path, PATH_MAX, EDID_PATH,
+ output->name) < PATH_MAX);
+
+ fd = open(edid_path, O_RDONLY);
+ if (fd == -1)
+ return false;
+
+ read_size = read(fd, sink_edid, EDID_SIZE);
+ close(fd);
+ if (read_size < 0)
+ return false;
+
+ /* Find Display Range Limits Descriptor block */
+ while (index < EDID_SIZE - range_head_size) {
+ for (i = 0; i < range_head_size; i++) {
+ if (sink_edid[index+i] != range_limits_head[i])
+ break;
+ else if (i == range_head_size-1) {
+ /* Found Display Range Limits Descriptor block */
+ parse_vrr_gange_from_edid(data, sink_edid, index);
+ return true;
+ }
+ }
+ index++;
+ }
+
+ return false;
+}
+
/* Check if EDID parsing is correctly reporting Freesync capability
* by overriding EDID with ones from golden sample.
*/
static void test_freesync_parsing_base(data_t *data, uint32_t test_flags)
{
const struct edid *edid;
- range_t range, expected_range;
+ struct vrr_range range, expected_range;
igt_output_t *output;
int j, test_conn_cnt = 0;
igt_display_t *display = &data->display;
@@ -277,15 +351,27 @@ static void test_freesync_parsing_base(data_t *data, uint32_t test_flags)
if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
igt_amd_allow_edp_hotplug_detect(data->fd, output->name, true);
- /* force to use hard coded VRR EDID */
- kmstest_force_edid(data->fd, output->config.connector, edid);
+ if (has_vrr(output)) {
+ /* A VRR sink, just parsing range from EDID directly */
+ trigger_edid_parse(data, output, test_flags);
- trigger_edid_parse(data, output, test_flags);
+ igt_assert_f(find_vrr_range_from_edid(data, output),
+ "Cannot parsing VRR range from EDID\n");
- range = get_freesync_range(data, output);
+ expected_range.min = data->expected_range.min;
+ expected_range.max = data->expected_range.max;
+ range = get_freesync_range(data, output);
+ } else {
+ /* force to use hard coded VRR EDID */
+ kmstest_force_edid(data->fd, output->config.connector, edid);
- /* undo EDID override. re-parse EDID of display */
- kmstest_force_edid(data->fd, output->config.connector, NULL);
+ trigger_edid_parse(data, output, test_flags);
+
+ range = get_freesync_range(data, output);
+
+ /* undo EDID override. re-parse EDID of display */
+ kmstest_force_edid(data->fd, output->config.connector, NULL);
+ }
igt_amd_trigger_hotplug(data->fd, output->name);
@@ -317,20 +403,13 @@ static inline void test_freesync_parsing_suspend(data_t *data)
test_freesync_parsing_base(data, TEST_SUSPEND);
}
-/* Returns true if an output supports VRR. */
-static bool has_vrr(igt_output_t *output)
-{
- return igt_output_has_prop(output, IGT_CONNECTOR_VRR_CAPABLE) &&
- igt_output_get_prop(output, IGT_CONNECTOR_VRR_CAPABLE);
-}
-
/* More relaxed checking on Freesync capability.
* Only checks if frame rate range is within legal range.
* Display under test MUST be VRR capable.
*/
static void test_freesync_range_base(data_t *data, uint32_t test_flags)
{
- range_t range;
+ struct vrr_range range;
igt_output_t *output;
int test_conn_cnt = 0;
igt_display_t *display = &data->display;
--
2.43.0
More information about the igt-dev
mailing list