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