[PATCH i-g-t,v2] tests/amdgpu/amd_vrr_range: Fix panel cannot light up after test
Leo Li
sunpeng.li at amd.com
Mon Jan 20 16:20:51 UTC 2025
On 2025-01-17 04:59, Tom Chung wrote:
> [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>
Reviewed-by: Leo Li <sunpeng.li at amd.com>
Thanks!
> ---
> v2: Move igt_amd_trigger_hotplug() to non-VRR sink only
>
> tests/amdgpu/amd_vrr_range.c | 140 +++++++++++++++++++++++++++--------
> 1 file changed, 110 insertions(+), 30 deletions(-)
>
> diff --git a/tests/amdgpu/amd_vrr_range.c b/tests/amdgpu/amd_vrr_range.c
> index 79db6f9c4..9d2462e5e 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;
> @@ -273,25 +347,38 @@ static void test_freesync_parsing_base(data_t *data, uint32_t test_flags)
> edid = (const struct edid *)edid_database[j].edid;
> expected_range = edid_database[j].range;
>
> - /* eDP allow read edid for each display detection */
> - if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
> - igt_amd_allow_edp_hotplug_detect(data->fd, output->name, true);
> + if (has_vrr(output)) {
> + /* A VRR sink, just parsing range from EDID directly */
>
> - /* force to use hard coded VRR EDID */
> - kmstest_force_edid(data->fd, output->config.connector, edid);
> + 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 {
> + /* A non-VRR sink. Override a golden EDID */
> + /* eDP allow read edid for each display detection */
> + if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
> + igt_amd_allow_edp_hotplug_detect(data->fd, output->name, true);
>
> - /* undo EDID override. re-parse EDID of display */
> - kmstest_force_edid(data->fd, output->config.connector, NULL);
> + /* force to use hard coded VRR EDID */
> + kmstest_force_edid(data->fd, output->config.connector, edid);
>
> - igt_amd_trigger_hotplug(data->fd, output->name);
> + trigger_edid_parse(data, output, test_flags);
>
> - /* eDP dis-allow read edid for each display detection */
> - if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
> - igt_amd_allow_edp_hotplug_detect(data->fd, output->name, false);
> + 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);
> +
> + /* eDP dis-allow read edid for each display detection */
> + if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
> + igt_amd_allow_edp_hotplug_detect(data->fd, output->name, false);
> + }
>
> test_conn_cnt++;
>
> @@ -317,20 +404,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;
More information about the igt-dev
mailing list