xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_fbcon_fbt.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2015 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors: Paulo Zanoni <[email protected]>
24  *
25  */
26 
27 #include "igt.h"
28 #include "igt_psr.h"
29 #include "igt_sysfs.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 
34 
35 IGT_TEST_DESCRIPTION("Test the relationship between fbcon and the frontbuffer "
36 		     "tracking infrastructure.");
37 
38 #define MAX_CONNECTORS 32
39 
40 static bool do_wait_user = false;
41 
42 struct drm_info {
43 	int fd;
44 	int debugfs_fd;
45 	drmModeResPtr res;
46 	drmModeConnectorPtr connectors[MAX_CONNECTORS];
47 };
48 
wait_user(const char * msg)49 static void wait_user(const char *msg)
50 {
51 	if (!do_wait_user)
52 		return;
53 
54 	igt_info("%s Press enter...\n", msg);
55 	while (getchar() != '\n')
56 		;
57 }
58 
setup_drm(struct drm_info * drm)59 static void setup_drm(struct drm_info *drm)
60 {
61 	int i;
62 
63 	if (drm->fd >= 0)
64 		return;
65 
66 	drm->fd = drm_open_driver_master(DRIVER_INTEL);
67 
68 	drm->res = drmModeGetResources(drm->fd);
69 	igt_require(drm->res);
70 	igt_assert(drm->res->count_connectors <= MAX_CONNECTORS);
71 
72 	for (i = 0; i < drm->res->count_connectors; i++)
73 		drm->connectors[i] = drmModeGetConnectorCurrent(drm->fd,
74 						drm->res->connectors[i]);
75 
76 	kmstest_set_vt_graphics_mode();
77 }
78 
teardown_drm(struct drm_info * drm)79 static void teardown_drm(struct drm_info *drm)
80 {
81 	int i;
82 
83 	kmstest_restore_vt_mode();
84 
85 	for (i = 0; i < drm->res->count_connectors; i++)
86 		drmModeFreeConnector(drm->connectors[i]);
87 
88 	drmModeFreeResources(drm->res);
89 	igt_assert(close(drm->fd) == 0);
90 	drm->fd = -1;
91 }
92 
fbc_supported_on_chipset(int debugfs_fd)93 static bool fbc_supported_on_chipset(int debugfs_fd)
94 {
95 	char buf[128];
96 	int ret;
97 
98 	ret = igt_debugfs_simple_read(debugfs_fd, "i915_fbc_status",
99 				      buf, sizeof(buf));
100 	if (ret < 0)
101 		return false;
102 
103 	return !strstr(buf, "FBC unsupported on this chipset\n");
104 }
105 
connector_can_fbc(drmModeConnectorPtr connector)106 static bool connector_can_fbc(drmModeConnectorPtr connector)
107 {
108 	return true;
109 }
110 
fbc_print_status(int debugfs_fd)111 static void fbc_print_status(int debugfs_fd)
112 {
113 	static char buf[128];
114 
115 	igt_debugfs_simple_read(debugfs_fd, "i915_fbc_status", buf,
116 				sizeof(buf));
117 	igt_debug("FBC status: %s\n", buf);
118 }
119 
fbc_is_enabled(int debugfs_fd)120 static bool fbc_is_enabled(int debugfs_fd)
121 {
122 	char buf[128];
123 
124 	igt_debugfs_simple_read(debugfs_fd, "i915_fbc_status", buf,
125 				sizeof(buf));
126 	return strstr(buf, "FBC enabled\n");
127 }
128 
fbc_wait_until_enabled(int debugfs_fd)129 static bool fbc_wait_until_enabled(int debugfs_fd)
130 {
131 	bool r = igt_wait(fbc_is_enabled(debugfs_fd), 5000, 1);
132 	fbc_print_status(debugfs_fd);
133 	return r;
134 }
135 
fbc_wait_until_update(int debugfs)136 static bool fbc_wait_until_update(int debugfs)
137 {
138 	/*
139 	 * FBC is not expected to be enabled because fbcon do not uses a tiled
140 	 * framebuffer so a fence can not be setup on the framebuffer and FBC
141 	 * code requires a fence to accurate track frontbuffer modifications
142 	 * (what maybe is not necessary anymore as we now have
143 	 * intel_fbc_invalidate()/flush()).
144 	 *
145 	 * If one day fbcon starts to use a tiled framebuffer we would need to
146 	 * check the 'Compressing' status as in each blink it would be disabled.
147 	 */
148 	return !fbc_wait_until_enabled(debugfs);
149 }
150 
151 typedef bool (*connector_possible_fn)(drmModeConnectorPtr connector);
152 
set_mode_for_one_screen(struct drm_info * drm,struct igt_fb * fb,connector_possible_fn connector_possible)153 static void set_mode_for_one_screen(struct drm_info *drm, struct igt_fb *fb,
154 				    connector_possible_fn connector_possible)
155 {
156 	int i, rc;
157 	uint32_t crtc_id;
158 	drmModeModeInfoPtr mode;
159 	uint32_t buffer_id;
160 	drmModeConnectorPtr c = NULL;
161 
162 	for (i = 0; i < drm->res->count_connectors; i++) {
163 		c = drm->connectors[i];
164 
165 		if (c->connection == DRM_MODE_CONNECTED && c->count_modes &&
166 		    connector_possible(c)) {
167 			mode = &c->modes[0];
168 			break;
169 		}
170 	}
171 	igt_require_f(i < drm->res->count_connectors,
172 		      "No connector available\n");
173 
174 	crtc_id = kmstest_find_crtc_for_connector(drm->fd, drm->res, c, 0);
175 
176 	buffer_id = igt_create_fb(drm->fd, mode->hdisplay, mode->vdisplay,
177 				  DRM_FORMAT_XRGB8888,
178 				  LOCAL_I915_FORMAT_MOD_X_TILED, fb);
179 	igt_draw_fill_fb(drm->fd, fb, 0xFF);
180 
181 	igt_info("Setting %dx%d mode for %s connector\n",
182 		 mode->hdisplay, mode->vdisplay,
183 		 kmstest_connector_type_str(c->connector_type));
184 
185 	rc = drmModeSetCrtc(drm->fd, crtc_id, buffer_id, 0, 0,
186 			    &c->connector_id, 1, mode);
187 	igt_assert_eq(rc, 0);
188 }
189 
connector_can_psr(drmModeConnectorPtr connector)190 static bool connector_can_psr(drmModeConnectorPtr connector)
191 {
192 	return (connector->connector_type == DRM_MODE_CONNECTOR_eDP);
193 }
194 
psr_print_status(int debugfs_fd)195 static void psr_print_status(int debugfs_fd)
196 {
197 	static char buf[PSR_STATUS_MAX_LEN];
198 
199 	igt_debugfs_simple_read(debugfs_fd, "i915_edp_psr_status", buf,
200 				sizeof(buf));
201 	igt_debug("PSR status: %s\n", buf);
202 }
203 
psr_wait_until_enabled(int debugfs_fd)204 static bool psr_wait_until_enabled(int debugfs_fd)
205 {
206 	bool r = psr_wait_entry(debugfs_fd, PSR_MODE_1);
207 
208 	psr_print_status(debugfs_fd);
209 	return r;
210 }
211 
psr_supported_on_chipset(int debugfs_fd)212 static bool psr_supported_on_chipset(int debugfs_fd)
213 {
214 	return psr_sink_support(debugfs_fd, PSR_MODE_1);
215 }
216 
psr_wait_until_update(int debugfs_fd)217 static bool psr_wait_until_update(int debugfs_fd)
218 {
219 	return psr_long_wait_update(debugfs_fd, PSR_MODE_1);
220 }
221 
disable_features(int debugfs_fd)222 static void disable_features(int debugfs_fd)
223 {
224 	igt_set_module_param_int("enable_fbc", 0);
225 	psr_disable(debugfs_fd);
226 }
227 
fbc_modparam_enable(int debugfs_fd)228 static inline void fbc_modparam_enable(int debugfs_fd)
229 {
230 	igt_set_module_param_int("enable_fbc", 1);
231 }
232 
psr_debugfs_enable(int debugfs_fd)233 static inline void psr_debugfs_enable(int debugfs_fd)
234 {
235 	psr_enable(debugfs_fd, PSR_MODE_1);
236 }
237 
238 struct feature {
239 	bool (*supported_on_chipset)(int debugfs_fd);
240 	bool (*wait_until_enabled)(int debugfs_fd);
241 	bool (*wait_until_update)(int debugfs_fd);
242 	bool (*connector_possible_fn)(drmModeConnectorPtr connector);
243 	void (*enable)(int debugfs_fd);
244 } fbc = {
245 	.supported_on_chipset = fbc_supported_on_chipset,
246 	.wait_until_enabled = fbc_wait_until_enabled,
247 	.wait_until_update = fbc_wait_until_update,
248 	.connector_possible_fn = connector_can_fbc,
249 	.enable = fbc_modparam_enable,
250 }, psr = {
251 	.supported_on_chipset = psr_supported_on_chipset,
252 	.wait_until_enabled = psr_wait_until_enabled,
253 	.wait_until_update = psr_wait_until_update,
254 	.connector_possible_fn = connector_can_psr,
255 	.enable = psr_debugfs_enable,
256 };
257 
subtest(struct drm_info * drm,struct feature * feature,bool suspend)258 static void subtest(struct drm_info *drm, struct feature *feature, bool suspend)
259 {
260 	struct igt_fb fb;
261 
262 	setup_drm(drm);
263 
264 	igt_require(feature->supported_on_chipset(drm->debugfs_fd));
265 
266 	disable_features(drm->debugfs_fd);
267 	feature->enable(drm->debugfs_fd);
268 
269 	kmstest_unset_all_crtcs(drm->fd, drm->res);
270 	wait_user("Modes unset.");
271 	igt_assert(!feature->wait_until_enabled(drm->debugfs_fd));
272 
273 	set_mode_for_one_screen(drm, &fb, feature->connector_possible_fn);
274 	wait_user("Screen set.");
275 	igt_assert(feature->wait_until_enabled(drm->debugfs_fd));
276 
277 	if (suspend) {
278 		igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
279 					      SUSPEND_TEST_NONE);
280 		sleep(5);
281 		igt_assert(feature->wait_until_enabled(drm->debugfs_fd));
282 	}
283 
284 	igt_remove_fb(drm->fd, &fb);
285 	teardown_drm(drm);
286 
287 	/* Wait for fbcon to restore itself. */
288 	sleep(3);
289 
290 	wait_user("Back to fbcon.");
291 	igt_assert(feature->wait_until_update(drm->debugfs_fd));
292 
293 	if (suspend) {
294 		igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
295 					      SUSPEND_TEST_NONE);
296 		sleep(5);
297 		igt_assert(feature->wait_until_update(drm->debugfs_fd));
298 	}
299 }
300 
setup_environment(struct drm_info * drm)301 static void setup_environment(struct drm_info *drm)
302 {
303 	int drm_fd;
304 
305 	drm_fd = drm_open_driver_master(DRIVER_INTEL);
306 	igt_require(drm_fd >= 0);
307 	drm->debugfs_fd = igt_debugfs_dir(drm_fd);
308 	igt_require(drm->debugfs_fd >= 0);
309 	igt_assert(close(drm_fd) == 0);
310 
311 	/*
312 	 * igt_main()->igt_subtest_init_parse_opts()->common_init() disables the
313 	 * fbcon bind, so to test it is necessary enable it again
314 	 */
315 	bind_fbcon(true);
316 	fbcon_blink_enable(true);
317 }
318 
teardown_environment(struct drm_info * drm)319 static void teardown_environment(struct drm_info *drm)
320 {
321 	if (drm->fd >= 0)
322 		teardown_drm(drm);
323 
324 	close(drm->debugfs_fd);
325 }
326 
327 igt_main
328 {
329 	struct drm_info drm = { .fd = -1 };
330 
331 	igt_fixture
332 		setup_environment(&drm);
333 
334 	igt_subtest("fbc")
335 		subtest(&drm, &fbc, false);
336 	igt_subtest("psr")
337 		subtest(&drm, &psr, false);
338 	igt_subtest("fbc-suspend")
339 		subtest(&drm, &fbc, true);
340 	igt_subtest("psr-suspend")
341 		subtest(&drm, &psr, true);
342 
343 	igt_fixture
344 		teardown_environment(&drm);
345 }
346