/* * Copyright © 2013 Intel Corporation * * 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 (including the next * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. * * Author: Paulo Zanoni * */ #include "igt.h" #include "igt_kmod.h" #include "igt_pm.h" #include "igt_sysfs.h" #include #include #include #include #define MAX_SINK_LPSP_INFO_BUF_LEN 4096 #define PWR_DOMAIN_INFO "i915_power_domain_info" typedef struct { int drm_fd; int debugfs_fd; uint32_t devid; char *pwr_dmn_info; igt_display_t display; struct igt_fb fb; drmModeModeInfo *mode; igt_output_t *output; } data_t; static bool lpsp_is_enabled(data_t *data) { char buf[MAX_SINK_LPSP_INFO_BUF_LEN]; int len; len = igt_debugfs_simple_read(data->debugfs_fd, "i915_lpsp_status", buf, sizeof(buf)); if (len < 0) igt_assert_eq(len, -ENODEV); igt_skip_on(strstr(buf, "LPSP: not supported")); return strstr(buf, "LPSP: enabled"); } static bool dmc_supported(int debugfs) { char buf[15]; int len; len = igt_sysfs_read(debugfs, "i915_dmc_info", buf, sizeof(buf) - 1); if (len < 0) return false; else return true; } /* * The LPSP mode is all about an enabled pipe, but we expect to also be in the * low power mode when no pipes are enabled, so do this check anyway. */ static void screens_disabled_subtest(data_t *data) { int valid_output = 0; for (int i = 0; i < data->display.n_outputs; i++) { data->output = &data->display.outputs[i]; igt_output_set_pipe(data->output, PIPE_NONE); igt_display_commit(&data->display); valid_output++; } igt_require_f(valid_output, "No connected output found\n"); /* eDP panel may have power_cycle_delay of 600ms, 1sec delay is safer */ igt_assert_f(igt_wait(lpsp_is_enabled(data), 1000, 100), "lpsp is not enabled\n%s:\n%s\n", PWR_DOMAIN_INFO, data->pwr_dmn_info = igt_sysfs_get(data->debugfs_fd, PWR_DOMAIN_INFO)); } static void setup_lpsp_output(data_t *data) { igt_plane_t *primary; /* set output pipe = PIPE_A for LPSP */ igt_output_set_pipe(data->output, PIPE_A); primary = igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(primary, NULL); igt_create_pattern_fb(data->drm_fd, data->mode->hdisplay, data->mode->vdisplay, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &data->fb); igt_plane_set_fb(primary, &data->fb); igt_display_commit(&data->display); } static void test_cleanup(data_t *data) { igt_plane_t *primary; if (!data->output || data->output->pending_pipe == PIPE_NONE) return; primary = igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(primary, NULL); igt_output_set_pipe(data->output, PIPE_NONE); igt_display_commit(&data->display); igt_remove_fb(data->drm_fd, &data->fb); data->output = NULL; } static void test_lpsp(data_t *data) { drmModeConnectorPtr c = data->output->config.connector; int i; /* LPSP is low power single pipe usages i.e. PIPE_A */ igt_require(igt_pipe_connector_valid(PIPE_A, data->output)); igt_require_f(i915_output_is_lpsp_capable(data->drm_fd, data->output), "output is not lpsp capable\n"); data->mode = igt_output_get_mode(data->output); /* For LPSP avoid pipe big joiner by atleast 4k mode */ if (data->mode->hdisplay > 3840 && data->mode->vdisplay > 2160) for (i = 0; i < c->count_modes; i++) { if (c->modes[i].hdisplay <= 3840 && c->modes[i].vdisplay <= 2160) { data->mode = &c->modes[i]; igt_output_override_mode(data->output, data->mode); break; } } igt_require(data->mode->hdisplay <= 3840 && data->mode->vdisplay <= 2160); setup_lpsp_output(data); igt_assert_f(igt_wait(lpsp_is_enabled(data), 1000, 100), "%s: lpsp is not enabled\n%s:\n%s\n", data->output->name, PWR_DOMAIN_INFO, data->pwr_dmn_info = igt_sysfs_get(data->debugfs_fd, PWR_DOMAIN_INFO)); } IGT_TEST_DESCRIPTION("These tests validates display Low Power Single Pipe configurations"); igt_main { data_t data = {}; igt_fixture { data.drm_fd = drm_open_driver_master(DRIVER_INTEL); igt_require(data.drm_fd >= 0); data.debugfs_fd = igt_debugfs_dir(data.drm_fd); igt_require(data.debugfs_fd >= 0); igt_pm_enable_audio_runtime_pm(); kmstest_set_vt_graphics_mode(); data.devid = intel_get_drm_devid(data.drm_fd); igt_display_require(&data.display, data.drm_fd); igt_require(igt_pm_dmc_loaded(data.debugfs_fd)); } igt_describe("This test validates lpsp while all crtc are disabled"); igt_subtest("screens-disabled") { igt_require_f(!dmc_supported(data.debugfs_fd), "DC states supported platform don't have ROI for this subtest\n"); screens_disabled_subtest(&data); } igt_describe("This test validates lpsp on all connected outputs on low power PIPE_A"); igt_subtest_with_dynamic_f("kms-lpsp") { igt_display_t *display = &data.display; igt_output_t *output; for_each_connected_output(display, output) { igt_dynamic_f("kms-lpsp-%s", kmstest_connector_type_str(output->config.connector->connector_type)) { data.output = output; test_lpsp(&data); } test_cleanup(&data); } } igt_fixture { free(data.pwr_dmn_info); close(data.drm_fd); igt_display_fini(&data.display); } }