blob: 3151ebb73fc644c8778cab4248d1f494af28b0e9 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass90b6fef2016-01-18 19:52:26 -07002/*
3 * Copyright (c) 2014 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass90b6fef2016-01-18 19:52:26 -07005 */
6
7#include <common.h>
8#include <bzlib.h>
9#include <dm.h>
10#include <mapmem.h>
11#include <os.h>
12#include <video.h>
13#include <video_console.h>
14#include <dm/test.h>
15#include <dm/uclass-internal.h>
16#include <test/ut.h>
17
18/*
19 * These tests use the standard sandbox frame buffer, the resolution of which
20 * is defined in the device tree. This only supports 16bpp so the tests only
21 * test that code path. It would be possible to adjust this fairly easily,
22 * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
23 * in sandbox_sdl_sync() would also need to change to handle the different
24 * surface depth.
25 */
Simon Glass90b6fef2016-01-18 19:52:26 -070026/* Basic test of the video uclass */
27static int dm_test_video_base(struct unit_test_state *uts)
28{
29 struct video_priv *priv;
30 struct udevice *dev;
31
32 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
33 ut_asserteq(1366, video_get_xsize(dev));
34 ut_asserteq(768, video_get_ysize(dev));
35 priv = dev_get_uclass_priv(dev);
36 ut_asserteq(priv->fb_size, 1366 * 768 * 2);
37
38 return 0;
39}
40DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
41
42/**
43 * compress_frame_buffer() - Compress the frame buffer and return its size
44 *
45 * We want to write tests which perform operations on the video console and
46 * check that the frame buffer ends up with the correct contents. But it is
47 * painful to store 'known good' images for comparison with the frame
48 * buffer. As an alternative, we can compress the frame buffer and check the
49 * size of the compressed data. This provides a pretty good level of
50 * certainty and the resulting tests need only check a single value.
51 *
52 * @dev: Video device
53 * @return compressed size of the frame buffer, or -ve on error
54 */
55static int compress_frame_buffer(struct udevice *dev)
56{
57 struct video_priv *priv = dev_get_uclass_priv(dev);
58 uint destlen;
59 void *dest;
60 int ret;
61
62 destlen = priv->fb_size;
63 dest = malloc(priv->fb_size);
64 if (!dest)
65 return -ENOMEM;
66 ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
67 priv->fb, priv->fb_size,
68 3, 0, 0);
69 free(dest);
70 if (ret)
71 return ret;
72
73 return destlen;
74}
75
76/*
77 * Call this function at any point to halt and show the current display. Be
78 * sure to run the test with the -l flag.
79 */
80static void __maybe_unused see_output(void)
81{
82 video_sync_all();
83 while (1);
84}
85
Simon Glassdaac9c72016-01-14 18:10:50 -070086/* Select the video console driver to use for a video device */
87static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
88{
89 struct sandbox_sdl_plat *plat;
90 struct udevice *dev;
91
92 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
93 ut_assert(!device_active(dev));
94 plat = dev_get_platdata(dev);
95 plat->vidconsole_drv_name = "vidconsole0";
96
97 return 0;
98}
99
Simon Glass90b6fef2016-01-18 19:52:26 -0700100/* Test text output works on the video console */
101static int dm_test_video_text(struct unit_test_state *uts)
102{
103 struct udevice *dev, *con;
104 int i;
105
106#define WHITE 0xffff
107#define SCROLL_LINES 100
108
Simon Glassdaac9c72016-01-14 18:10:50 -0700109 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700110 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
111 ut_asserteq(46, compress_frame_buffer(dev));
112
113 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
114 vidconsole_putc_xy(con, 0, 0, 'a');
115 ut_asserteq(79, compress_frame_buffer(dev));
116
117 vidconsole_putc_xy(con, 0, 0, ' ');
118 ut_asserteq(46, compress_frame_buffer(dev));
119
120 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700121 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700122 ut_asserteq(273, compress_frame_buffer(dev));
123
124 vidconsole_set_row(con, 0, WHITE);
125 ut_asserteq(46, compress_frame_buffer(dev));
126
127 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700128 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700129 ut_asserteq(273, compress_frame_buffer(dev));
130
131 return 0;
132}
133DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
134
135/* Test handling of special characters in the console */
136static int dm_test_video_chars(struct unit_test_state *uts)
137{
138 struct udevice *dev, *con;
Simon Glass37b80202016-01-14 18:10:38 -0700139 const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest \bman\n\t\tand Has much to\b\bto be modest about.";
Simon Glass90b6fef2016-01-18 19:52:26 -0700140
Simon Glassdaac9c72016-01-14 18:10:50 -0700141 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700142 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
143 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400144 vidconsole_put_string(con, test_string);
Simon Glass90b6fef2016-01-18 19:52:26 -0700145 ut_asserteq(466, compress_frame_buffer(dev));
146
147 return 0;
148}
149DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
150
Rob Clark09d64b32017-09-25 15:45:09 -0400151#ifdef CONFIG_VIDEO_ANSI
152#define ANSI_ESC "\x1b"
153/* Test handling of ANSI escape sequences */
154static int dm_test_video_ansi(struct unit_test_state *uts)
155{
156 struct udevice *dev, *con;
157
158 ut_assertok(select_vidconsole(uts, "vidconsole0"));
159 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
160 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
161
162 /* reference clear: */
163 video_clear(con->parent);
Simon Glass0806dcc2018-10-01 11:55:14 -0600164 video_sync(con->parent, false);
Rob Clark09d64b32017-09-25 15:45:09 -0400165 ut_asserteq(46, compress_frame_buffer(dev));
166
167 /* test clear escape sequence: [2J */
168 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
169 ut_asserteq(46, compress_frame_buffer(dev));
170
171 /* test set-cursor: [%d;%df */
172 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
Heinrich Schuchardtc3c69302018-11-10 19:55:48 +0100173 ut_asserteq(143, compress_frame_buffer(dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400174
175 /* test colors (30-37 fg color, 40-47 bg color) */
176 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
177 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
Heinrich Schuchardtc3c69302018-11-10 19:55:48 +0100178 ut_asserteq(272, compress_frame_buffer(dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400179
180 return 0;
181}
182DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
183#endif
184
Simon Glass90b6fef2016-01-18 19:52:26 -0700185/**
186 * check_vidconsole_output() - Run a text console test
187 *
188 * @uts: Test state
189 * @rot: Console rotation (0, 90, 180, 270)
190 * @wrap_size: Expected size of compressed frame buffer for the wrap test
191 * @scroll_size: Same for the scroll test
192 * @return 0 on success
193 */
194static int check_vidconsole_output(struct unit_test_state *uts, int rot,
195 int wrap_size, int scroll_size)
196{
197 struct udevice *dev, *con;
198 struct sandbox_sdl_plat *plat;
199 int i;
200
201 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
202 ut_assert(!device_active(dev));
203 plat = dev_get_platdata(dev);
204 plat->rot = rot;
205
206 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
207 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
208 ut_asserteq(46, compress_frame_buffer(dev));
209
210 /* Check display wrap */
211 for (i = 0; i < 120; i++)
212 vidconsole_put_char(con, 'A' + i % 50);
213 ut_asserteq(wrap_size, compress_frame_buffer(dev));
214
215 /* Check display scrolling */
216 for (i = 0; i < SCROLL_LINES; i++) {
217 vidconsole_put_char(con, 'A' + i % 50);
218 vidconsole_put_char(con, '\n');
219 }
220 ut_asserteq(scroll_size, compress_frame_buffer(dev));
221
222 /* If we scroll enough, the screen becomes blank again */
223 for (i = 0; i < SCROLL_LINES; i++)
224 vidconsole_put_char(con, '\n');
225 ut_asserteq(46, compress_frame_buffer(dev));
226
227 return 0;
228}
229
230/* Test text output through the console uclass */
231static int dm_test_video_context(struct unit_test_state *uts)
232{
Simon Glassdaac9c72016-01-14 18:10:50 -0700233 ut_assertok(select_vidconsole(uts, "vidconsole0"));
234 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
235
236 return 0;
Simon Glass90b6fef2016-01-18 19:52:26 -0700237}
238DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassa0f1efe2016-01-18 19:52:27 -0700239
240/* Test rotated text output through the console uclass */
241static int dm_test_video_rotation1(struct unit_test_state *uts)
242{
243 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
244
245 return 0;
246}
247DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
248
249/* Test rotated text output through the console uclass */
250static int dm_test_video_rotation2(struct unit_test_state *uts)
251{
252 ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
253
254 return 0;
255}
256DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
257
258/* Test rotated text output through the console uclass */
259static int dm_test_video_rotation3(struct unit_test_state *uts)
260{
261 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
262
263 return 0;
264}
265DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7a1cb292016-01-18 19:52:28 -0700266
267/* Read a file into memory and return a pointer to it */
268static int read_file(struct unit_test_state *uts, const char *fname,
269 ulong *addrp)
270{
271 int buf_size = 100000;
272 ulong addr = 0;
273 int size, fd;
274 char *buf;
275
276 buf = map_sysmem(addr, 0);
277 ut_assert(buf != NULL);
278 fd = os_open(fname, OS_O_RDONLY);
279 ut_assert(fd >= 0);
280 size = os_read(fd, buf, buf_size);
Simon Glass9050c5f2016-01-30 15:45:17 -0700281 os_close(fd);
Simon Glass7a1cb292016-01-18 19:52:28 -0700282 ut_assert(size >= 0);
283 ut_assert(size < buf_size);
Simon Glass7a1cb292016-01-18 19:52:28 -0700284 *addrp = addr;
285
286 return 0;
287}
288
289/* Test drawing a bitmap file */
290static int dm_test_video_bmp(struct unit_test_state *uts)
291{
292 struct udevice *dev;
293 ulong addr;
294
295 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
296 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
297
298 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
299 ut_asserteq(1368, compress_frame_buffer(dev));
300
301 return 0;
302}
303DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
304
305/* Test drawing a compressed bitmap file */
306static int dm_test_video_bmp_comp(struct unit_test_state *uts)
307{
308 struct udevice *dev;
309 ulong addr;
310
311 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
312 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
313
314 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
315 ut_asserteq(1368, compress_frame_buffer(dev));
316
317 return 0;
318}
319DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass32337982016-01-14 18:10:51 -0700320
321/* Test TrueType console */
322static int dm_test_video_truetype(struct unit_test_state *uts)
323{
324 struct udevice *dev, *con;
325 const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
Simon Glass32337982016-01-14 18:10:51 -0700326
327 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
328 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400329 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100330 ut_asserteq(12237, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700331
332 return 0;
333}
334DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
335
336/* Test scrolling TrueType console */
337static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
338{
339 struct sandbox_sdl_plat *plat;
340 struct udevice *dev, *con;
341 const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
Simon Glass32337982016-01-14 18:10:51 -0700342
343 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
344 ut_assert(!device_active(dev));
345 plat = dev_get_platdata(dev);
346 plat->font_size = 100;
347
348 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
349 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400350 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100351 ut_asserteq(35030, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700352
353 return 0;
354}
355DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
356
357/* Test TrueType backspace, within and across lines */
358static int dm_test_video_truetype_bs(struct unit_test_state *uts)
359{
360 struct sandbox_sdl_plat *plat;
361 struct udevice *dev, *con;
362 const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things.";
Simon Glass32337982016-01-14 18:10:51 -0700363
364 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
365 ut_assert(!device_active(dev));
366 plat = dev_get_platdata(dev);
367 plat->font_size = 100;
368
369 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
370 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400371 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100372 ut_asserteq(29018, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700373
374 return 0;
375}
376DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);