[igt-dev] [PATCH i-g-t v2] tests/amdgpu: Add test for Adaptive Backlight Management

David Francis David.Francis at amd.com
Thu Jan 3 19:32:28 UTC 2019


Adaptive Backlight Management (ABM) is a power-saving
feature on AMD ASICs that reduces backlight while increasing
pixel contrast and luminance.  This test confirms that
ABM is present and enabled, and that backlight performance
is sane.  It uses AMD-specific debugfs entries to
read the backlight PWM values.

It has 5 subtests:

dpms_cycle
Sets brightness to half, then confirms that value is restored
after dpms off and then on.

backlight_monotonic_basic
Sets brightness to ten different values, confirming that
higher brightness values are brighter.

backlight_monotonic_abm
Same as backlight_monotonic_basic, but with abm enabled.

abm_enabled
Sets abm to its four intensity levels, confirming that
abm reduces the backlight, and the reduction is greater
for higher abm level.

abm_gradual
Sets abm to off and then maximum intensity, confirming
that brightness decreases continually over the first
second and eventually reaches the target value.
This test takes 30s to run.

v2: make sure that dpms is cycled on the eDP display

Signed-off-by: David Francis <David.Francis at amd.com>
---
 tests/Makefile.sources |   1 +
 tests/amdgpu/amd_abm.c | 363 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 364 insertions(+)
 create mode 100644 tests/amdgpu/amd_abm.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 5620c1d6..3d560bee 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -19,6 +19,7 @@ AMDGPU_TESTS = \
 	amdgpu/amd_basic \
 	amdgpu/amd_cs_nop \
 	amdgpu/amd_prime \
+	amdgpu/amd_abm \
 	$(NULL)
 
 TESTS_progs = \
diff --git a/tests/amdgpu/amd_abm.c b/tests/amdgpu/amd_abm.c
new file mode 100644
index 00000000..363b1e90
--- /dev/null
+++ b/tests/amdgpu/amd_abm.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2018 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 "drmtest.h"
+#include "igt_kms.h"
+#include <limits.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+
+#define BACKLIGHT_PATH "/sys/class/backlight/amdgpu_bl0"
+
+static int read_current_backlight_pwm(int debugfs_dir)
+{
+	char buf[20];
+
+	igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",
+			 buf, sizeof(buf));
+
+	return strtol(buf, NULL, 0);
+}
+
+static int read_target_backlight_pwm(int debugfs_dir)
+{
+	char buf[20];
+
+	igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",
+			 buf, sizeof(buf));
+
+	return strtol(buf, NULL, 0);
+}
+
+static int backlight_write_brightness(int value)
+{
+	int fd;
+	char full[PATH_MAX];
+	char src[64];
+	int len;
+
+	igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "brightness") < PATH_MAX);
+	fd = open(full, O_WRONLY);
+	if (fd == -1)
+		return -errno;
+
+	len = snprintf(src, sizeof(src), "%i", value);
+	len = write(fd, src, len);
+	close(fd);
+
+	if (len < 0)
+		return len;
+
+	return 0;
+}
+
+static void set_abm_level(igt_display_t *display, int level)
+{
+	int i, ret;
+	int output_id;
+	drmModeObjectPropertiesPtr props;
+	uint32_t prop_id;
+	drmModePropertyPtr prop;
+	uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
+
+	for (i = 0; i < display->n_outputs; i++) {
+		output_id = display->outputs[i].id;
+		props = drmModeObjectGetProperties(display->drm_fd, output_id, type);
+
+		for (i = 0; i < props->count_props; i++) {
+			prop_id = props->props[i];
+			prop = drmModeGetProperty(display->drm_fd, prop_id);
+
+			igt_assert(prop);
+
+			if (strcmp(prop->name, "abm level") == 0) {
+				ret = drmModeObjectSetProperty(display->drm_fd, output_id, type, prop_id, level);
+
+				igt_assert_eq(ret, 0);
+			}
+
+			drmModeFreeProperty(prop);
+		}
+	}
+
+}
+
+static int backlight_read_max_brightness(int *result)
+{
+	int fd;
+	char full[PATH_MAX];
+	char dst[64];
+	int r, e;
+
+	igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "max_brightness") < PATH_MAX);
+
+	fd = open(full, O_RDONLY);
+	if (fd == -1)
+		return -errno;
+
+	r = read(fd, dst, sizeof(dst));
+	e = errno;
+	close(fd);
+
+	if (r < 0)
+		return -e;
+
+	errno = 0;
+	*result = strtol(dst, NULL, 10);
+	return errno;
+}
+
+static void skip_if_incompatible(igt_display_t *display, int debugfs_dir)
+{
+	int ret, i;
+	char buf[20];
+	bool abm_prop_exists;
+	int output_id;
+	drmModeObjectPropertiesPtr props;
+	uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
+	uint32_t prop_id;
+	drmModePropertyPtr prop;
+
+	ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",
+			 buf, sizeof(buf));
+
+	if (ret < 0)
+		igt_skip("No current backlight debugfs entry.\n");
+
+	ret = igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",
+			 buf, sizeof(buf));
+
+	if (ret < 0)
+		igt_skip("No target backlight debugfs entry.\n");
+
+	abm_prop_exists = false;
+
+	for (i = 0; i < display->n_outputs; i++) {
+		output_id = display->outputs[i].id;
+		props = drmModeObjectGetProperties(display->drm_fd, output_id, type);
+
+		for (i = 0; i < props->count_props; i++) {
+			prop_id = props->props[i];
+			prop = drmModeGetProperty(display->drm_fd, prop_id);
+
+			if (strcmp(prop->name, "abm level") == 0)
+				abm_prop_exists = true;
+
+			drmModeFreeProperty(prop);
+		}
+	}
+
+	if (!abm_prop_exists)
+		igt_skip("No abm level property on any connector.\n");
+}
+
+
+static void backlight_dpms_cycle(igt_display_t *display, int debugfs, igt_output_t *output)
+{
+	int ret;
+	int max_brightness;
+	int pwm_1, pwm_2;
+
+	ret = backlight_read_max_brightness(&max_brightness);
+	igt_assert_eq(ret, 0);
+
+	set_abm_level(display, 0);
+	backlight_write_brightness(max_brightness / 2);
+	usleep(100000);
+	pwm_1 = read_target_backlight_pwm(debugfs);
+
+	kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF);
+	kmstest_set_connector_dpms(display->drm_fd, output->config.connector, DRM_MODE_DPMS_ON);
+	usleep(100000);
+	pwm_2 = read_target_backlight_pwm(debugfs);
+	igt_assert_eq(pwm_1, pwm_2);
+}
+
+static void backlight_monotonic_basic(igt_display_t *display, int debugfs)
+{
+	int ret;
+	int max_brightness;
+	int prev_pwm, pwm;
+	int brightness_step;
+	int brightness;
+
+	ret = backlight_read_max_brightness(&max_brightness);
+	igt_assert_eq(ret, 0);
+
+	brightness_step = max_brightness / 10;
+
+	set_abm_level(display, 0);
+	backlight_write_brightness(max_brightness);
+	usleep(100000);
+	prev_pwm = read_target_backlight_pwm(debugfs);
+	for (brightness = max_brightness - brightness_step;
+	     brightness > 0;
+	     brightness -= brightness_step) {
+		backlight_write_brightness(brightness);
+		usleep(100000);
+		pwm = read_target_backlight_pwm(debugfs);
+		igt_assert(pwm < prev_pwm);
+		prev_pwm = pwm;
+	}
+
+}
+
+static void backlight_monotonic_abm(igt_display_t *display, int debugfs)
+{
+	int ret, i;
+	int max_brightness;
+	int prev_pwm, pwm;
+	int brightness_step;
+	int brightness;
+
+	ret = backlight_read_max_brightness(&max_brightness);
+	igt_assert_eq(ret, 0);
+
+	brightness_step = max_brightness / 10;
+	for (i = 1; i < 5; i++) {
+		set_abm_level(display, i);
+		backlight_write_brightness(max_brightness);
+		usleep(100000);
+		prev_pwm = read_target_backlight_pwm(debugfs);
+		for (brightness = max_brightness - brightness_step;
+		     brightness > 0;
+		     brightness -= brightness_step) {
+			backlight_write_brightness(brightness);
+			usleep(100000);
+			pwm = read_target_backlight_pwm(debugfs);
+			igt_assert(pwm < prev_pwm);
+			prev_pwm = pwm;
+		}
+	}
+}
+
+static void abm_enabled(igt_display_t *display, int debugfs)
+{
+	int ret, i;
+	int max_brightness;
+	int pwm, prev_pwm, pwm_without_abm;
+
+	ret = backlight_read_max_brightness(&max_brightness);
+	igt_assert_eq(ret, 0);
+
+	set_abm_level(display, 0);
+	backlight_write_brightness(max_brightness);
+	usleep(100000);
+	prev_pwm = read_target_backlight_pwm(debugfs);
+	pwm_without_abm = prev_pwm;
+
+	for (i = 1; i < 5; i++) {
+		set_abm_level(display, i);
+		usleep(100000);
+		pwm = read_target_backlight_pwm(debugfs);
+		igt_assert(pwm <= prev_pwm);
+		igt_assert(pwm < pwm_without_abm);
+		prev_pwm = pwm;
+	}
+
+}
+
+static void abm_gradual(igt_display_t *display, int debugfs)
+{
+	int ret, i;
+	int convergence_delay = 15;
+	int prev_pwm, pwm, curr;
+	int max_brightness;
+
+	ret = backlight_read_max_brightness(&max_brightness);
+
+	igt_assert_eq(ret, 0);
+
+	set_abm_level(display, 0);
+	backlight_write_brightness(max_brightness);
+
+	sleep(convergence_delay);
+	prev_pwm = read_target_backlight_pwm(debugfs);
+	curr = read_current_backlight_pwm(debugfs);
+
+	igt_assert_eq(prev_pwm, curr);
+	set_abm_level(display, 4);
+	for (i = 0; i < 10; i++) {
+		usleep(100000);
+		pwm = read_current_backlight_pwm(debugfs);
+		igt_assert(pwm < prev_pwm);
+		prev_pwm = pwm;
+	}
+
+	sleep(convergence_delay - 1);
+
+	prev_pwm = read_target_backlight_pwm(debugfs);
+	curr = read_current_backlight_pwm(debugfs);
+
+	igt_assert_eq(prev_pwm, curr);
+}
+
+igt_main
+{
+	igt_display_t display;
+	int debugfs;
+	enum pipe pipe;
+	igt_output_t *output;
+
+	igt_skip_on_simulation();
+
+	igt_fixture {
+		display.drm_fd = drm_open_driver_master(DRIVER_AMDGPU);
+
+		if (display.drm_fd == -1)
+			igt_skip("Not an amdgpu driver.\n");
+
+		debugfs = igt_debugfs_dir(display.drm_fd);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_require(&display, display.drm_fd);
+
+		skip_if_incompatible(&display, debugfs);
+
+		for_each_pipe_with_valid_output(&display, pipe, output) {
+			if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+				break;
+		}
+	}
+
+	igt_subtest("dpms_cycle")
+		backlight_dpms_cycle(&display, debugfs, output);
+	igt_subtest("backlight_monotonic_basic")
+		backlight_monotonic_basic(&display, debugfs);
+	igt_subtest("backlight_monotonic_abm")
+		backlight_monotonic_abm(&display, debugfs);
+	igt_subtest("abm_enabled")
+		abm_enabled(&display, debugfs);
+	igt_subtest("abm_gradual")
+		abm_gradual(&display, debugfs);
+
+	igt_fixture {
+		igt_display_fini(&display);
+	}
+}
-- 
2.17.1



More information about the igt-dev mailing list